【数据结构】二叉树-C语言版(三)

简介: 【数据结构】二叉树-C语言版

二叉树应用

1.单值二叉树 OJ链接

分析:判断所有节点的值是否相等,当根值等于左孩子的值并且根值等于右孩子的值时,需要递归判断左子树的根值是否等于其左孩子的值并且左子树的根值等于其右孩子的值,并且需要递归判断右子树的根值是否等于其左孩子的值并且右子树的根值等于其右孩子的值······

1. /**
2.  * Definition for a binary tree node.
3.  * struct TreeNode {
4.  *     int val;
5.  *     struct TreeNode *left;
6.  *     struct TreeNode *right;
7.  * };
8.  */
9. 
10. bool isUnivalTree(struct TreeNode* root){
11.     if(root == NULL)
12.     {
13.         return true;
14.     }
15.    
16.     if((root->left) && (root->left->val != root->val))    
17.     {
18.         return false;
19.     }
20. 
21.     if((root->right) && (root->right->val != root->val))    
22.     {
23.         return false;
24.     }
25. 
26.     return isUnivalTree(root->left) && isUnivalTree(root->right);
27. }

2.二叉树的前序遍历 OJ链接

分析:要求返回数组必须是malloc的,但是需要malloc多大的空间呢?malloc树的结点总数个空间,因此要

(1)求树的节点个数

(2)递归遍历整棵树,将根节点存到数组中

1. /**
2.  * Definition for a binary tree node.
3.  * struct TreeNode {
4.  *     int val;
5.  *     struct TreeNode *left;
6.  *     struct TreeNode *right;
7.  * };
8.  */
9. 
10. 
11. /**
12.  * Note: The returned array must be malloced, assume caller calls free().
13.  */
14. 
15. //求树的大小
16. int TreeSize(struct TreeNode* root)
17. {
18.   return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
19. }
20. 
21. void _preorder(struct TreeNode* root,int * arr,int* pi)
22. {
23.     if(root == NULL)
24.     {
25.         return;
26.     }
27. 
28.     //将根节点保存起来
29.     arr[(*pi)++] = root->val;
30.     _preorder(root->left,arr,pi);
31.     _preorder(root->right,arr,pi);
32. }
33. 
34. int* preorderTraversal(struct TreeNode* root, int* returnSize){
35.     *returnSize = TreeSize(root);
36. 
37.     //申请树的节点个数大小空间
38.     int* arr = (int*)malloc(sizeof(int)*(*returnSize));
39.     int i = 0;
40.     _preorder(root,arr,&i);
41.     
42.     return arr;
43. }

 3.相同的树  OJ链接

分析:需要结构相同且结点有相同的值

(1)结构相同可以用递归遍历左右子树的根节点是否存在来判断

(2)值是否相同可以用递归遍历左右子树的根节点值是否相等来判断

1. /**
2.  * Definition for a binary tree node.
3.  * struct TreeNode {
4.  *     int val;
5.  *     struct TreeNode *left;
6.  *     struct TreeNode *right;
7.  * };
8.  */
9. 
10. bool isSameTree(struct TreeNode* p, struct TreeNode* q){
11.     //左右子树都为空
12.     if((p == NULL) && (q == NULL))
13.     {
14.         return true;
15.     }
16. 
17.     //左子树为空,右子树不为空
18.     if((p == NULL) && (q != NULL))
19.     {
20.         return false;
21.     }
22. 
23.     //左子树不为空,右子树为空
24.     if((p != NULL) && (q == NULL))
25.     {
26.         return false;
27.     }
28. 
29.     //左右子树都不为空
30.     if((p != NULL) && (q != NULL))
31.     {
32.         if(p->val == q->val)
33.         {
34.             return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
35.         }     
36.     }
37.     return false;
38. }

4.对称二叉树 OJ链接

分析:

(1)判断二叉树是否对称,需要判断左孩子和右孩子的结点值是否相等,就需要递归判断左孩子的左孩子值和右孩子的右孩子值是否相等······

(2)给出的函数只有一个入参,需要判断左右孩子值是否相等,最好重新写一个函数,同时入参左右结点

1. /**
2.  * Definition for a binary tree node.
3.  * struct TreeNode {
4.  *     int val;
5.  *     TreeNode *left;
6.  *     TreeNode *right;
7.  *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
8.  *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
9.  *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
10.  * };
11.  */
12. 
13. bool _isSymmetric(struct TreeNode* left,struct TreeNode* right)
14. {
15.     if(left == NULL && right == NULL)
16.     {
17.         return true;
18.     }
19.     if(left == NULL && right != NULL)
20.     {
21.         return false;
22.     }
23.     if(left != NULL && right == NULL)
24.     {
25.         return false;
26.     }
27.  
28.     if(left->val == right->val)
29.     {
30.         return _isSymmetric(left->left,right->right) && _isSymmetric(left->right,right->left);
31.     }
32.       
33.     return false;
34. }
35.    
36. bool isSymmetric(struct TreeNode* root) {
37.     if(root == NULL)
38.     {
39.         return true;
40.     }
41.  
42.     return _isSymmetric(root->left,root->right);
43. }

5.平衡二叉树  OJ链接

方法一:

(1)求出左右子树的高度,如果高度差<=1,则是平衡二叉树

(2)平衡二叉树要求以每个结点为根的子树都是平衡的,因此要递归判断每个子结点是否是平衡的

1. /**
2.  * Definition for a binary tree node.
3.  * struct TreeNode {
4.  *     int val;
5.  *     struct TreeNode *left;
6.  *     struct TreeNode *right;
7.  * };
8.  */
9. 
10. int TreeDepth(struct TreeNode* root)
11.     {
12.         if(root == NULL)
13.         {
14.             return 0;
15.         }
16.         return fmax(TreeDepth(root->left),TreeDepth(root->right))+1;
17.     }
18. bool isBalanced(struct TreeNode* root) {
19.     if(root == NULL)
20.     {
21.         return true;
22.     }
23.     return fabs(TreeDepth(root->left)-TreeDepth(root->right)) < 2
24.          &&isBalanced(root->left)
25.          &&isBalanced(root->right);
26. }

方法二:判断左子树是否平衡的同时判断右子树是否平衡,同时把高度带给上一层父亲,让父亲计算父亲为根节点的子树高度

1. bool _isBalanced(struct TreeNode* root,int* ph)
2. {
3.     if(root == NULL)
4.     {
5.         *ph = 0;
6.         return true;
7.     }
8. 
9.     //后序
10.     //先判断左子树,再判断右子树
11.     int leftHeight= 0;
12.     if(_isBalanced(root->left,&leftHeight) == false)
13.     {
14.         return false;
15.     }
16. 
17.     int rightHeight = 0;
18.     if(_isBalanced(root->right,&rightHeight) == false)
19.     {
20.         return false;
21.     }
22. 
23.     //同时再把高度带给上一层父亲
24.     *ph = fmax(leftHeight,rightHeight) + 1;
25.     return abs(leftHeight - rightHeight) < 2;
26. }
27. 
28. bool isBalanced(struct TreeNode* root) {
29.     int height = 0;
30.     return _isBalanced(root,&height);
31. }

6.另一棵树的子树   OJ链接

分析:(1)遍历root的每个结点,每个结点做根和subRoot比较是否相等

          (2)如何判断树相等,前面已经已经有代码

1. /**
2.  * Definition for a binary tree node.
3.  * struct TreeNode {
4.  *     int val;
5.  *     struct TreeNode *left;
6.  *     struct TreeNode *right;
7.  * };
8.  */
9. 
10. 
11. bool isSameTree(struct TreeNode* p, struct TreeNode* q){
12.     //左右子树都为空
13.     if((p == NULL) && (q == NULL))
14.     {
15.         return true;
16.     }
17. 
18.     //左子树为空,右子树不为空
19.     if((p == NULL) && (q != NULL))
20.     {
21.         return false;
22.     }
23. 
24.     //左子树不为空,右子树为空
25.     if((p != NULL) && (q == NULL))
26.     {
27.         return false;
28.     }
29. 
30.     //左右子树都不为空
31.     if((p != NULL) && (q != NULL))
32.     {
33.         if(p->val == q->val)
34.         {
35.             return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
36.         }     
37.     }
38.     return false;
39. }
40. 
41. bool isSubtree(struct TreeNode* root,struct  TreeNode* subRoot) {
42.     //遍历root的每个结点,每个结点做子树的根和subRoot比较是否相等
43.     if(root == NULL)
44.     {
45.         return false;
46.     }
47. 
48.     //每个结点作为子树根和subRoot进行比较
49.     if(isSameTree(root,subRoot))
50.     {
51.         return true;
52.     }
53. 
54.     return isSubtree(root->left,subRoot) 
55.         || isSubtree(root->right,subRoot);
56. }

7.二叉树遍历 OJ链接

分析:

(1)构建树:遇到#就忽略跳到下一个字符,递归构建左右子树

(2)中序遍历

1. #include<stdio.h>
2. #include<stdlib.h>
3. 
4. typedef struct TreeNode
5. {
6.     struct TreeNode* left;
7.     struct TreeNode* right;
8.     char val;
9. }TreeNode;
10. 
11. TreeNode* CreateTree(char* str, int* pi)
12. {
13.     if (str[*pi] == '#')
14.     {
15.         ++(*pi);
16.         return NULL;
17.     }
18. 
19.     //不是#,构造根
20.     TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));
21.     if (root != NULL)
22.     {
23.         root->val = str[*pi];
24.         ++(*pi);
25.     }
26.     
27. 
28.     //递归构建左子树
29.     root->left = CreateTree(str, pi);
30. 
31.     //递归构建右子树
32.     root->right = CreateTree(str, pi);
33.     return root;
34. }
35. 
36. void Inorder(TreeNode* root)
37. {
38.     if (root == NULL)
39.     {
40.         return;
41.     }
42. 
43.     Inorder(root->left);
44.     printf("%c ", root->val);
45.     Inorder(root->right);
46. }
47. 
48. int main()
49. {
50.     char str[100];
51.     scanf("%s", str);
52. 
53.     int i = 0;
54.     TreeNode* root = CreateTree(str, &i);
55.     Inorder(root);
56.     printf("\n");
57. 
58.     return 0;
59. }
相关文章
|
17天前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
|
17天前
|
C语言
数据结构基础详解(C语言):图的基本概念_无向图_有向图_子图_生成树_生成森林_完全图
本文介绍了图的基本概念,包括图的定义、无向图与有向图、简单图与多重图等,并解释了顶点度、路径、连通性等相关术语。此外还讨论了子图、生成树、带权图及几种特殊形态的图,如完全图和树等。通过这些概念,读者可以更好地理解图论的基础知识。
|
19天前
|
存储 算法 C语言
数据结构基础详解(C语言): 二叉树的遍历_线索二叉树_树的存储结构_树与森林详解
本文从二叉树遍历入手,详细介绍了先序、中序和后序遍历方法,并探讨了如何构建二叉树及线索二叉树的概念。接着,文章讲解了树和森林的存储结构,特别是如何将树与森林转换为二叉树形式,以便利用二叉树的遍历方法。最后,讨论了树和森林的遍历算法,包括先根、后根和层次遍历。通过这些内容,读者可以全面了解二叉树及其相关概念。
|
19天前
|
存储 算法 C语言
C语言手撕实战代码_二叉树_构造二叉树_层序遍历二叉树_二叉树深度的超详细代码实现
这段代码和文本介绍了一系列二叉树相关的问题及其解决方案。其中包括根据前序和中序序列构建二叉树、通过层次遍历序列和中序序列创建二叉树、计算二叉树节点数量、叶子节点数量、度为1的节点数量、二叉树高度、特定节点子树深度、判断两棵树是否相似、将叶子节点链接成双向链表、计算算术表达式的值、判断是否为完全二叉树以及求二叉树的最大宽度等。每道题目均提供了详细的算法思路及相应的C/C++代码实现,帮助读者理解和掌握二叉树的基本操作与应用。
|
19天前
|
存储 C语言
数据结构基础详解(C语言): 树与二叉树的应用_哈夫曼树与哈夫曼曼编码_并查集_二叉排序树_平衡二叉树
本文详细介绍了树与二叉树的应用,涵盖哈夫曼树与哈夫曼编码、并查集以及二叉排序树等内容。首先讲解了哈夫曼树的构造方法及其在数据压缩中的应用;接着介绍了并查集的基本概念、存储结构及优化方法;随后探讨了二叉排序树的定义、查找、插入和删除操作;最后阐述了平衡二叉树的概念及其在保证树平衡状态下的插入和删除操作。通过本文,读者可以全面了解树与二叉树在实际问题中的应用技巧和优化策略。
|
19天前
|
存储 算法 C语言
C语言手撕数据结构代码_顺序表_静态存储_动态存储
本文介绍了基于静态和动态存储的顺序表操作实现,涵盖创建、删除、插入、合并、求交集与差集、逆置及循环移动等常见操作。通过详细的C语言代码示例,展示了如何高效地处理顺序表数据结构的各种问题。
|
算法 C语言
C语言数据结构(15)--二叉树的前序、中序、后序遍历
本文目录 1. 背景 2. 前序遍历 3. 中序遍历 4. 后序遍历 5. 层序遍历 6. 代码实现
344 0
C语言数据结构(15)--二叉树的前序、中序、后序遍历
|
16天前
|
存储 Serverless C语言
【C语言基础考研向】11 gets函数与puts函数及str系列字符串操作函数
本文介绍了C语言中的`gets`和`puts`函数,`gets`用于从标准输入读取字符串直至换行符,并自动添加字符串结束标志`\0`。`puts`则用于向标准输出打印字符串并自动换行。此外,文章还详细讲解了`str`系列字符串操作函数,包括统计字符串长度的`strlen`、复制字符串的`strcpy`、比较字符串的`strcmp`以及拼接字符串的`strcat`。通过示例代码展示了这些函数的具体应用及注意事项。
|
19天前
|
存储 C语言
C语言程序设计核心详解 第十章:位运算和c语言文件操作详解_文件操作函数
本文详细介绍了C语言中的位运算和文件操作。位运算包括按位与、或、异或、取反、左移和右移等六种运算符及其复合赋值运算符,每种运算符的功能和应用场景都有具体说明。文件操作部分则涵盖了文件的概念、分类、文件类型指针、文件的打开与关闭、读写操作及当前读写位置的调整等内容,提供了丰富的示例帮助理解。通过对本文的学习,读者可以全面掌握C语言中的位运算和文件处理技术。
|
19天前
|
存储 C语言
C语言程序设计核心详解 第七章 函数和预编译命令
本章介绍C语言中的函数定义与使用,以及预编译命令。主要内容包括函数的定义格式、调用方式和示例分析。C程序结构分为`main()`单框架或多子函数框架。函数不能嵌套定义但可互相调用。变量具有类型、作用范围和存储类别三种属性,其中作用范围分为局部和全局。预编译命令包括文件包含和宏定义,宏定义分为无参和带参两种形式。此外,还介绍了变量的存储类别及其特点。通过实例详细解析了函数调用过程及宏定义的应用。