【数据结构C/C++】顺序与链式二叉树创建与前中后、层序遍历

文章目录

  • 顺序存储结构二叉树
  • 链式存储结构二叉树
  • 刷题推荐
  • 408考研各数据结构C/C++代码(Continually updating)

顺序存储结构二叉树

顺序存储结构的二叉树的特点在于,其使用数组存放二叉树中的每一个节点。
我们设定根节点的数组索引下标为n(n>=1),那么有当前根节点的左子树节点在数组中的下标为2n,右子树在数组中的下标为2n+1。
上面是顺序存储结构二叉树的最最最重要的一个特性,我们后面的所有操作都基于这个理论。
相对于比较简单的对于链式存储结构的二叉树的遍历,以及计算最大二叉树深度,链式存储结构都会更加接单,而顺序存储结构则需要考虑到当前节点是否为空,并且当前索引是否超出了树当前最大的节点个数。

LeetCode计算二叉树最大深度
在这里插入图片描述

这里我不推荐你花大把时间去实现一个顺序存储结构的二叉树的层序遍历,因为我们知道,层序遍历一般的解法都是配合一个队列或者栈来实现的。
我在写Java的时候一般都会使用Deque也就是双端队列来实现,但是C语言并没有提供这样子的功能,你还得手动实现,比较费时,因此我不太推荐。
当然,有兴趣的可以去刷一下LeetCode链式存储结构的层序遍历,还是比较常见的。

先附上一张代码运行的图片。
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>#define MaxSize 100typedef char TreeNodeType;//二叉树结构
typedef struct
{TreeNodeType data[MaxSize];int BiTreeNum;
} BinaryTree;// 声明队列数据结构
typedef struct
{int front, rear;int size;int capacity;int *array;
} Queue;void initTree(BinaryTree *T);
void createTree(BinaryTree *T, int n);
TreeNodeType rootTree(BinaryTree *T);
int countTree(BinaryTree *T);
int maxDepthOfTree(BinaryTree *T, int n);
void preOrderTraverse(BinaryTree *T, int n);
void inOrderTraverse(BinaryTree *T, int n);
void postOrderTraverse(BinaryTree *T, int n);
void levelOrderTraverse(BinaryTree *T); // 层序遍历
bool destoryTree(BinaryTree *T);
void traverseArray(BinaryTree *T); // 遍历数组// 队列相关函数
Queue *createQueue(int capacity);
bool isQueueEmpty(Queue *queue);
bool isQueueFull(Queue *queue);
void enqueue(Queue *queue, int item);
int dequeue(Queue *queue);int main()
{BinaryTree T;// 开始构造二叉树 其中使用1作为根节点下标// 而不是使用0,使用0的问题在于不好表示数据在数组中的位置// 我们知道二叉树满足 当前节点n的左子树和右子树的序列号应该为 2n和2n+1initTree(&T);printf("请输入根结点(输入#表示该结点为空):");createTree(&T, 1);traverseArray(&T);printf("当前二叉树的最大深度为:%d\n", maxDepthOfTree(&T, 1));printf("先序遍历:");preOrderTraverse(&T, 1);printf("\n");printf("中序遍历:");inOrderTraverse(&T, 1);printf("\n");printf("后序遍历:");postOrderTraverse(&T, 1);printf("\n");printf("层序遍历:");levelOrderTraverse(&T);printf("\n");return 0;
}void initTree(BinaryTree *T)
{int i;for (i = 0; i < MaxSize; ++i){T->data[i] = '\0';}T->BiTreeNum = 0;return;
}void createTree(BinaryTree *T, int n)
{char ch;// 刷新(清空)标准输入流(stdin)// 主打一个求稳fflush(stdin);// 输入当前节点信息 # 代表当前节点为空// 先构造过字数scanf(" %c", &ch);if (ch == '#'){ // 空直接返回return;}else{T->data[n] = ch;T->BiTreeNum++;printf("输入 %c 的左子树数据(输入#表示当前左子树为空: ", ch);// 这里有一个技巧createTree(T, 2 * n);printf("输入 %c 的右子树数据(输入#表示当前右边子树为空): ", ch);createTree(T, (2 * n + 1));}
}// 计算二叉树的最大深度
// 从根节点到叶子节点的最长路径的长度
// 由于是顺序结构 因此这里从第一层也就是n=1开始向下遍历
// 然后不断的判断左子树和右子树的高度
// 最后取最大值
int maxDepthOfTree(BinaryTree *T, int n)
{if (n <= T->BiTreeNum && T->data[n] != '\0'){int leftDepth = maxDepthOfTree(T, 2 * n);int rightDepth = maxDepthOfTree(T, 2 * n + 1);return 1 + fmax(leftDepth, rightDepth);}else{return 0;}
}//先序遍历 根左右
void preOrderTraverse(BinaryTree *T, int n)
{if (T->data[n] == '\0')return;else{printf("%c ", T->data[n]);preOrderTraverse(T, 2 * n);preOrderTraverse(T, (2 * n + 1));}
}
//中序遍历 左根由7
void inOrderTraverse(BinaryTree *T, int n)
{if (T->data[n] == '\0')return;else{inOrderTraverse(T, 2 * n);printf("%c ", T->data[n]);inOrderTraverse(T, (2 * n + 1));}
}
//后序遍历  左右根
void postOrderTraverse(BinaryTree *T, int n)
{if (T->data[n] == '\0')return;else{postOrderTraverse(T, 2 * n);postOrderTraverse(T, (2 * n + 1));printf("%c ", T->data[n]);}
}
void traverseArray(BinaryTree *T){for(int i=1;i<=T->BiTreeNum;i++){printf("%c  ",T->data[i]);}printf("\n");
}// 层序遍历二叉树
void levelOrderTraverse(BinaryTree *T)
{if (T->BiTreeNum == 0){printf("二叉树为空\n");return;}//创建一个队列存放当前层Queue *queue = createQueue(T->BiTreeNum);int current = 1; // 从根节点开始//结束条件while (current <= T->BiTreeNum){printf("%c ", T->data[current]);//判断左子树是否存在 存在就放入队列if (2 * current <= T->BiTreeNum && T->data[2 * current] != '\0'){enqueue(queue, 2 * current);}//判断右子树是否存在 存在就放入队列if (2 * current + 1 <= T->BiTreeNum && T->data[2 * current + 1] != '\0'){enqueue(queue, 2 * current + 1);}//出队对头 if (!isQueueEmpty(queue)){current = dequeue(queue);}else{break;}}//使用完毕释放空间free(queue->array);free(queue);
}// 创建队列
Queue *createQueue(int capacity)
{Queue *queue = (Queue *)malloc(sizeof(Queue));if (!queue){perror("内存分配失败");exit(EXIT_FAILURE);}queue->front = 0;queue->rear = -1;queue->size = 0;queue->capacity = capacity;queue->array = (int *)malloc(capacity * sizeof(int));if (!queue->array){perror("内存分配失败");exit(EXIT_FAILURE);}return queue;
}// 检查队列是否为空
bool isQueueEmpty(Queue *queue)
{return (queue->size == 0);
}// 检查队列是否已满
bool isQueueFull(Queue *queue)
{return (queue->size == queue->capacity);
}// 入队列
void enqueue(Queue *queue, int item)
{if (isQueueFull(queue)){printf("队列已满\n");return;}queue->rear = (queue->rear + 1) % queue->capacity;queue->array[queue->rear] = item;queue->size++;
}// 出队列
int dequeue(Queue *queue)
{if (isQueueEmpty(queue)){printf("队列为空\n");return -1;}int item = queue->array[queue->front];queue->front = (queue->front + 1) % queue->capacity;queue->size--;return item;
}

链式存储结构二叉树

链式存储结构构造一个二叉树就比较简单,并且无论是遍历操作还是追求最大深度,都可以比较容易的求解。
其主要的重点在于结构体的定义,链式存储结构的精髓在于,左右指针域。

// 定义二叉树结点结构
typedef struct TreeNode
{int data;struct TreeNode *left; //左右指针struct TreeNode *right;
} TreeNode;

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>#define MaxSize 100
// 定义二叉树结点结构
typedef struct TreeNode
{int data;struct TreeNode *left;struct TreeNode *right;
} TreeNode;// 函数声明
TreeNode *createNode(int data);
TreeNode *insert(TreeNode *root, int data);
TreeNode *search(TreeNode *root, int data);
TreeNode *findMin(TreeNode *root);
TreeNode *deleteNode(TreeNode *root, int data);
void preorderTraversal(TreeNode *root);
void inorderTraversal(TreeNode *root);
void postorderTraversal(TreeNode *root);
int maxDepthOfTree(TreeNode *root);
void levelOrderTraversal(TreeNode *root);TreeNode *root = NULL;int main()
{int choice, data;printf("基于链式存储结构的二叉树操作:\n");while (1){printf("\n请选择操作:\n");printf("1. 插入\n");printf("2. 删除\n");printf("3. 查找\n");printf("4. 层序遍历\n");scanf("%d", &choice);switch (choice){case 1:printf("输入要插入的数据: ");scanf("%d", &data);root = insert(root, data);printf("前序遍历结果为:");preorderTraversal(root);printf("中序遍历结果为:");inorderTraversal(root);printf("后序遍历结果为:");postorderTraversal(root);printf("二叉树最大深度为:%d\n", maxDepthOfTree(root));break;case 2:printf("输入要删除的数据: ");scanf("%d", &data);root = deleteNode(root, data);printf("前序遍历结果为:");preorderTraversal(root);printf("中序遍历结果为:");inorderTraversal(root);printf("后序遍历结果为:");postorderTraversal(root);printf("二叉树最大深度为:%d\n", maxDepthOfTree(root));break;case 3:printf("输入要查找的数据: ");scanf("%d", &data);TreeNode *result = search(root, data);if (result != NULL){printf("找到了 %d\n", result->data);}else{printf("未找到 %d\n", data);}printf("前序遍历结果为:");preorderTraversal(root);printf("中序遍历结果为:");inorderTraversal(root);printf("后序遍历结果为:");postorderTraversal(root);printf("二叉树最大深度为:%d\n", maxDepthOfTree(root));break;case 4:printf("层序遍历结果为:");levelOrderTraversal(root);printf("\n");break;}}return 0;
}// 创建新的二叉树结点
TreeNode *createNode(int data)
{TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode));if (newNode == NULL){perror("内存分配失败");exit(EXIT_FAILURE);}newNode->data = data;newNode->left = NULL;newNode->right = NULL;return newNode;
}// 插入结点
TreeNode *insert(TreeNode *root, int data)
{if (root == NULL){return createNode(data);}if (data < root->data){root->left = insert(root->left, data);}else if (data > root->data){root->right = insert(root->right, data);}return root;
}// 查找结点
TreeNode *search(TreeNode *root, int data)
{if (root == NULL || root->data == data){return root;}if (data < root->data){return search(root->left, data);}else{return search(root->right, data);}
}// 找到最小值结点
TreeNode *findMin(TreeNode *root)
{while (root->left != NULL){root = root->left;}return root;
}// 删除结点
TreeNode *deleteNode(TreeNode *root, int data)
{if (root == NULL){return root;}if (data < root->data){root->left = deleteNode(root->left, data);}else if (data > root->data){root->right = deleteNode(root->right, data);}else{// 结点有一个子结点或没有子结点if (root->left == NULL){TreeNode *temp = root->right;free(root);return temp;}else if (root->right == NULL){TreeNode *temp = root->left;free(root);return temp;}// 结点有两个子结点,找到中序遍历的后继结点(右子树中的最小值)TreeNode *temp = findMin(root->right);root->data = temp->data;root->right = deleteNode(root->right, temp->data);}return root;
}// 前序遍历
void preorderTraversal(TreeNode *root)
{if (root != NULL){printf("%d ", root->data);preorderTraversal(root->left);preorderTraversal(root->right);}
}// 中序遍历
void inorderTraversal(TreeNode *root)
{if (root != NULL){inorderTraversal(root->left);printf("%d ", root->data);inorderTraversal(root->right);}
}// 后序遍历
void postorderTraversal(TreeNode *root)
{if (root != NULL){postorderTraversal(root->left);postorderTraversal(root->right);printf("%d ", root->data);}
}// 计算二叉树的最大深度
int maxDepthOfTree(TreeNode *root)
{if (root == NULL){return 0;}else{int leftHeight = maxDepthOfTree(root->left);int rightHeight = maxDepthOfTree(root->right);return fmax(leftHeight, rightHeight) + 1;}
}// 层序遍历
void levelOrderTraversal(TreeNode *root)
{if (root == NULL){return;}// 创建一个队列用于层序遍历TreeNode *queue[MaxSize];int front = 0, rear = 0;queue[rear++] = root; // 根结点入队while (front < rear){TreeNode *current = queue[front++];printf("%d ", current->data);// 左子结点入队if (current->left != NULL){queue[rear++] = current->left;}// 右子结点入队if (current->right != NULL){queue[rear++] = current->right;}}
}

刷题推荐

LeetCode树类型题目
树类型的题目其实是我刷的最多的,因为其实只要找到规律了,做起来就最快,直接往递归这一条路上去考虑即可。
在这里插入图片描述

408考研各数据结构C/C++代码(Continually updating)

408考研各数据结构C/C++代码(Continually updating)
这个模块是我应一些朋友的需求,希望我能开一个专栏,专门提供考研408中各种常用的数据结构的代码,并且希望我附上比较完整的注释以及提供用户输入功能,ok,fine,这个专栏会一直更新,直到我认为没有新的数据结构可以讲解了。
目前我比较熟悉的数据结构如下:
数组、链表、队列、栈、树、B/B+树、红黑树、Hash、图。
所以我会先有空更新出如下几个数据结构的代码,欢迎关注。 当然,在我前两年的博客中,对于链表、哈夫曼树等常用数据结构,我都提供了比较完整的详细的实现以及思路讲解,有兴趣可以去考古。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/130017.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MM-Camera架构-ProcessCaptureRequest 流程分析

文章目录 processCaptureRequest\_3\_41.1 mDevice1.2 mDevice->ops->process\_capture\_request1.3 hardware to vendor mct\_shimlayer\_process\_event2.1 mct\_shimlayer\_handle\_parm2.2 mct\_shimlayer\_reg\_buffer processCaptureRequest_3_4 sdm660的摄像头走…

js Learn(异步JavaScript)

在这个模块中&#xff0c;我们来看看异步JavaScript&#xff0c;为什么它很重要&#xff0c;以及如何使用它来有效地处理潜在的阻塞操作&#xff0c;比如从服务器获取资源。 指南 异步JavaScript介绍 在本文中&#xff0c;我们将学习同步&#xff08;synchronous&#xff09…

非凸科技受邀出席源创会,探讨数据技术的未来发展

9月23日&#xff0c;由开源中国联合腾讯云TVP开展的“数据与前沿技术”源创会活动在成都顺利举行&#xff0c;非凸科技受邀出席&#xff0c;与业界专家们共同探讨了数据存储、数据分析、数据挖掘等前沿技术。 会上&#xff0c;非凸科技成都分公司研发总监赵海峰以“量化交易的数…

班级文化建设方案分享 中学高中建设方案

班级文化建设方案 一、基本信息 名称&#xff1a;xxxx计划 时间&#xff1a;XXXX年XX月-XXXX年XX月 地点&#xff1a;[XXXXX] 参与人群&#xff1a;X班全体师生及家长 目的和宗旨&#xff1a;通过班级文化建设&#xff0c;营造积极向上的班级氛围&#xff0c;增强班级凝聚…

嵌入式养成计划-31-网络编程----TCP的并发服务器模型------IO模型--IO多路复用

六十七、 TCP的并发服务器模型 67.1 循环服务器模型 一次只能处理一个客户端&#xff0c;当上一个客户端退出后&#xff0c;才能处理下一个客户端缺点&#xff1a;无法同时处理多个客户端 代码模型 sfd socket(); bind(); listen(); while(1){newfd accept();while(1){re…

web基础及http协议

web基础 全称 world wide web 全球广域网也就是万维网 web1.0 只能看 web2.0 页面交互&#xff1a;静态页面和动态页面 静态页面url&#xff1a;文本文件&#xff0c;可以修改&#xff0c;一般以html .htm保存的文本文件。网站的基础。静态页面和后台数据库没有任何交互不包含…

找到所有数组中消失的数字

题目链接 找到所有数组中消失的数字 题目描述 注意点 在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题 解答思路 要想找到消失的数字需要使用哈希表&#xff0c;因为本题要在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题&#xff0c;而所有数字出现…

安全性第一!OpenWRT配置SFTP远程文件传输,实现数据安全保护

文章目录 前言1. openssh-sftp-server 安装2. 安装cpolar工具3.配置SFTP远程访问4.固定远程连接地址 前言 本次教程我们将在OpenWRT上安装SFTP服务&#xff0c;并结合cpolar内网穿透&#xff0c;创建安全隧道映射22端口&#xff0c;实现在公网环境下远程OpenWRT SFTP&#xff…

如何使用Docker轻松构建和管理应用程序(一)

如今Docker的使用已经非常普遍&#xff0c;特别在一线互联网公司。使用Docker技术可以帮助企业快速水平扩展服务&#xff0c;从而到达弹性部署业务的能力。在云服务概念兴起之后&#xff0c;Docker的使用场景和范围进一步发展&#xff0c;如今在微服务架构越来越流行的情况下&a…

信息增益,经验熵和经验条件熵——决策树

目录 1.经验熵 2.经验条件熵 3.信息增益 4.增益比率 5.例子1 6.例子2 在决策树模型中&#xff0c;我们会考虑应该选择哪一个特征作为根节点最好&#xff0c;这里就用到了信息增益 通俗上讲&#xff0c;信息增益就是在做出判断时&#xff0c;该信息对你影响程度的大小。比…

数字孪生与GIS数据为何高度互补?二者融合后能达到什么样的效果?

山海鲸可视化作为一款数字孪生软件&#xff0c;在GIS的融合方面处于业内领先水平&#xff0c;那么为什么一款数字孪生软件要花费巨大的精力&#xff0c;去实现GIS的融合&#xff0c;实现后又能达到什么样的效果呢&#xff1f;下面就让我们来一探究竟。 一、为什么数字孪生需要…

Java使用模板导出word、pdf

使用deepoove根据模板导出word文档&#xff0c;包括文本、表格、图表、图片&#xff0c;使用WordConvertPdf可将word文档转换为pdf导出 模板样例&#xff1a; 导出结果&#xff1a; 一、引入相关依赖 <!-- 工具类--><dependency><groupId>cn.hutool&…