C/C++数据结构-完整代码(四)队列【Queue】(树和二叉树)(二叉树代码实现)

x33g5p2x  于2021-09-25 转载在 C/C++  
字(11.9k)|赞(0)|评价(0)|浏览(546)

一、树的基本概念

1、树的定义

由一个或多个(n≥0)结点组成的有限集合T ,

有且仅有一个结点称为根( root ) ,

当n>1时,

其余的结点分为m(m≥0)个互不相交的有限集合T1,T2,…,Tm。

每个集合本身又是棵树,被称作这个根的子树。

2、树的结构特点

  • 非线性结构,有一个直接前驱,但可能有多个直接后继( 1:n )
  • 树的定义具有递归性,树中还有树。
  • 树可以为空,即节点个数为0。

3、若干术语

  • →即根结点(没有前驱)
  • 叶子→即终端结点(没有后继)
  • 森林→指m棵不相交的树的集合(例如删除A后的子树个数)
  • 有序树→结点各子树从左至右有序,不能互换(左为第一)
  • 无序树→结点各子树可互换位置。
  • 双亲→即上层的那个结点(直接前驱) parent
  • 孩子→即下层结点的子树(直接后继)child-
  • 兄弟→同一双亲下的同层结点(孩子之间互称兄弟) siblinge
  • 堂兄弟→即双亲位于同一层的结点(但并非同一双亲) cousin
  • 祖先→即从根到该结点所经分支的所有结点
  • 子孙→即该结点下层子树中的任一结点

  • 结点→即树的数据元素
  • 结点的度→结点挂接的子树数(有几个直接后继就是几度)
  • 结点的层次→从根到该结点的层数(根结点算第一层)
  • 终端结点→即度为0的结点,即叶子
  • 分支结点→除树根以外的结点(也称为内部结点)
  • 树的度→所有结点度中的最大值( Max{各结点的度})
  • 树的深度(或高度)→指所有结点中最大的层数(Max{各结点的层次})
  1. 上图中的结点数 = 13 ,树的度 = 3 ,数的深度 = 4

二、树的表示法

1、图形表示法

事物之问的逻辑关系可以通过数的形式很直观的表示出来,如下图:

2、广义表示法

用广义表表示法表示上图:

  1. 中国(河北(保定,石家庄),广东(广州,东莞),山东(青岛,济南))

根作为由子树森林组成的表的名宁写在表的左边。

3、左孩子右兄弟表示法

左孩子右兄弟表示法可以将一颗多叉树转化为一颖二叉树:

三、二叉树的概念

1、二叉树的基本概念

(1)定义:

n ( n≥0 )个结点的有限集合,由一个根结点以及两棵互不相交的、分别称为左子树和
右子树的二叉树组成。

(2)逻辑结构:

一对二(1:2)

(3)基本特性

每个结点最多只有两棵子树(丕存在度大于2的结点);

左子树和右子树次序不能颠倒(有序树)

(4)基本形态

2、二叉树的性质

3、满二叉树

特点:每层都有”充满”了结点

4、完全二叉树

除最后一层外,每一层上的节点均达到最大值;在最后一层上只缺少右边的若干结点

理解:k-1层与满二叉树完全相同,第k层结点尽量靠左

(1)性质4:具有n个结点的完全二叉树的深度必为

(2)性质5:对完全二叉树,若从上到下,从左到右编号,则编号为i的结点,其左孩子编号为2i,其右孩子编号必为2i+1 ,其双亲的编号必为i/2(i=1时为根除外)

四、二叉树编程

1、二叉树的遍历

(1)遍历定义

指按某条搜索路线遍访每个结点且不重复(又称周游入

(2)遍历用途

它是树结构插入、删除、修改、查找和排序运算的前提,是二叉树一切运算的基础和核
心。

(3)遍历方法

牢记一种约定,对每个结点的查看都是“先左后右”。
限定先左后右,树的遍历有三种实现方案∶

  • DLR一先序遍历,即先根再左再右
  • LDR一中序遍历,即先左再根再右
  • LRD一后序遍历,即先左再右再根

注:"先、中、后”的意思是指访问的结点D是先于子树出现还是后于子树出现。

从递归的角度看,这三种算法是完全相同的,

或者说这三种遍历算法的访问路径是相同的,

只是访问结点的时机不同。

从虚线的出发点到终点的路径上,每个结点经过3次。

  • 第1次经过时访问=先序遍历
  • 第2次经过时访问=中序遍历
  • 第3次经过时访问=后序遍历

先序遍历:根 左 右

中序遍历:左 根 右

后续遍历:左 右 根

2、二叉树的遍历(代码实现)

(1)先序变量
  1. #include <stdio.h>
  2. #include "string.h"
  3. #include "stdlib.h"
  4. struct BinaryNode{
  5. char ch;//数据域
  6. struct BinaryNode * LChild;//左孩子节点
  7. struct BinaryNode * RChild;//右孩子节点
  8. };
  9. //递归遍历的函数
  10. void recursion(struct BinaryNode * root){
  11. if(root == NULL){
  12. return;
  13. }
  14. //先序遍历,先根 再左 再右
  15. printf ("%c ",root->ch);
  16. recursion (root->LChild);
  17. recursion (root->RChild);
  18. }
  19. void test01(){
  20. struct BinaryNode nodeA = {'A',NULL,NULL};
  21. struct BinaryNode nodeB = {'B',NULL,NULL};
  22. struct BinaryNode nodeC = {'C',NULL,NULL};
  23. struct BinaryNode nodeD = {'D',NULL,NULL};
  24. struct BinaryNode nodeE = {'E',NULL,NULL};
  25. struct BinaryNode nodeF = {'F',NULL,NULL};
  26. struct BinaryNode nodeG = {'G',NULL,NULL};
  27. struct BinaryNode nodeH = {'H',NULL,NULL};
  28. //建立结点之间的关系
  29. nodeA.LChild = &nodeB;
  30. nodeA.RChild = &nodeF;
  31. nodeB.RChild = &nodeC;
  32. nodeC.LChild = &nodeD;
  33. nodeC.RChild = &nodeE;
  34. nodeF.RChild = &nodeG;
  35. nodeG.LChild = &nodeH;
  36. //递归遍历
  37. recursion(&nodeA);
  38. }
  39. int main () {
  40. test01();
  41. return 0;
  42. }

运行结果

(2)下面代码依次实现中序和后序遍历代码
  1. #include <stdio.h>
  2. #include "string.h"
  3. #include "stdlib.h"
  4. struct BinaryNode{
  5. char ch;//数据域
  6. struct BinaryNode * LChild;//左孩子节点
  7. struct BinaryNode * RChild;//右孩子节点
  8. };
  9. //递归遍历的函数
  10. void preorderRecursion(struct BinaryNode * root){
  11. if(root == NULL){
  12. return;
  13. }
  14. //先序遍历,先根 再左 再右
  15. printf ("%c ",root->ch);
  16. preorderRecursion (root->LChild);
  17. preorderRecursion (root->RChild);
  18. }
  19. //递归遍历的函数
  20. void inRecursion(struct BinaryNode * root){
  21. if(root == NULL){
  22. return;
  23. }
  24. //中序遍历,先根 再左 再右
  25. inRecursion (root->LChild);
  26. printf ("%c ",root->ch);
  27. inRecursion (root->RChild);
  28. }
  29. //递归遍历的函数
  30. void afterRecursion(struct BinaryNode * root){
  31. if(root == NULL){
  32. return;
  33. }
  34. //中序遍历,先根 再左 再右
  35. afterRecursion (root->LChild);
  36. afterRecursion (root->RChild);
  37. printf ("%c ",root->ch);
  38. }
  39. void test01(){
  40. struct BinaryNode nodeA = {'A',NULL,NULL};
  41. struct BinaryNode nodeB = {'B',NULL,NULL};
  42. struct BinaryNode nodeC = {'C',NULL,NULL};
  43. struct BinaryNode nodeD = {'D',NULL,NULL};
  44. struct BinaryNode nodeE = {'E',NULL,NULL};
  45. struct BinaryNode nodeF = {'F',NULL,NULL};
  46. struct BinaryNode nodeG = {'G',NULL,NULL};
  47. struct BinaryNode nodeH = {'H',NULL,NULL};
  48. //建立结点之间的关系
  49. nodeA.LChild = &nodeB;
  50. nodeA.RChild = &nodeF;
  51. nodeB.RChild = &nodeC;
  52. nodeC.LChild = &nodeD;
  53. nodeC.RChild = &nodeE;
  54. nodeF.RChild = &nodeG;
  55. nodeG.LChild = &nodeH;
  56. //递归遍历
  57. printf("先序遍历\n");
  58. preorderRecursion(&nodeA);
  59. printf("\n中序遍历\n");
  60. inRecursion(&nodeA);
  61. printf("\n后序遍历\n");
  62. afterRecursion(&nodeA);
  63. }
  64. int main () {
  65. test01();
  66. return 0;
  67. }

运行结果

3、计算二叉树的叶子结点

  1. #include <stdio.h>
  2. #include "string.h"
  3. #include "stdlib.h"
  4. struct BinaryNode{
  5. char ch;//数据域
  6. struct BinaryNode * LChild;//左孩子节点
  7. struct BinaryNode * RChild;//右孩子节点
  8. };
  9. //统计叶子数量的函数
  10. void calculateLeafNum(struct BinaryNode * root, int * num){
  11. //递归的结束条件
  12. if(root == NULL){
  13. return;
  14. }
  15. //判断当前节点的左孩子和右孩子是否为空。如果为空数字就累加
  16. if(root->LChild == NULL && root->RChild == NULL){
  17. (*num)++;
  18. }
  19. calculateLeafNum (root->LChild,num);
  20. calculateLeafNum (root->RChild,num);
  21. }
  22. void test01(){
  23. struct BinaryNode nodeA = {'A',NULL,NULL};
  24. struct BinaryNode nodeB = {'B',NULL,NULL};
  25. struct BinaryNode nodeC = {'C',NULL,NULL};
  26. struct BinaryNode nodeD = {'D',NULL,NULL};
  27. struct BinaryNode nodeE = {'E',NULL,NULL};
  28. struct BinaryNode nodeF = {'F',NULL,NULL};
  29. struct BinaryNode nodeG = {'G',NULL,NULL};
  30. struct BinaryNode nodeH = {'H',NULL,NULL};
  31. //建立结点之间的关系
  32. nodeA.LChild = &nodeB;
  33. nodeA.RChild = &nodeF;
  34. nodeB.RChild = &nodeC;
  35. nodeC.LChild = &nodeD;
  36. nodeC.RChild = &nodeE;
  37. nodeF.RChild = &nodeG;
  38. nodeG.LChild = &nodeH;
  39. //求树中的叶子的数量
  40. int num = 0;
  41. calculateLeafNum(&nodeA ,&num);
  42. printf ("LeafNum=%d",num);
  43. }
  44. int main () {
  45. test01();
  46. return 0;
  47. }

4、计算树的深度/高度

  1. int getTreeHeight(struct BinaryNode* root){
  2. if(root == NULL){
  3. return 0;
  4. }
  5. //求出左子树的高度
  6. int LHeight = getTreeHeight(root->LChild);
  7. //计算右子树的高度
  8. int RHeight = getTreeHeight(root->RChild);
  9. //取左子树和右子树,中最大的值 +1
  10. int height = LHeight > RHeight ? LHeight + 1 : RHeight + 1;
  11. return height;
  12. }

计算相关的所有代码

  1. #include <stdio.h>
  2. struct BinaryNode{
  3. char ch;//数据域
  4. struct BinaryNode * LChild;//左孩子节点
  5. struct BinaryNode * RChild;//右孩子节点
  6. };
  7. //统计叶子数量的函数
  8. void calculateLeafNum(struct BinaryNode * root, int * num){
  9. //递归的结束条件
  10. if(root == NULL){
  11. return;
  12. }
  13. //判断当前节点的左孩子和右孩子是否为空。如果为空数字就累加
  14. if(root->LChild == NULL && root->RChild == NULL){
  15. (*num)++;
  16. }
  17. calculateLeafNum (root->LChild,num);
  18. calculateLeafNum (root->RChild,num);
  19. }
  20. int getTreeHeight(struct BinaryNode* root){
  21. if(root == NULL){
  22. return 0;
  23. }
  24. //求出左子树的高度
  25. int LHeight = getTreeHeight(root->LChild);
  26. //计算右子树的高度
  27. int RHeight = getTreeHeight(root->RChild);
  28. //取左子树和右子树,中最大的值 +1
  29. int height = LHeight > RHeight ? LHeight + 1 : RHeight + 1;
  30. return height;
  31. }
  32. void test01(){
  33. struct BinaryNode nodeA = {'A',NULL,NULL};
  34. struct BinaryNode nodeB = {'B',NULL,NULL};
  35. struct BinaryNode nodeC = {'C',NULL,NULL};
  36. struct BinaryNode nodeD = {'D',NULL,NULL};
  37. struct BinaryNode nodeE = {'E',NULL,NULL};
  38. struct BinaryNode nodeF = {'F',NULL,NULL};
  39. struct BinaryNode nodeG = {'G',NULL,NULL};
  40. struct BinaryNode nodeH = {'H',NULL,NULL};
  41. //建立结点之间的关系
  42. nodeA.LChild = &nodeB;
  43. nodeA.RChild = &nodeF;
  44. nodeB.RChild = &nodeC;
  45. nodeC.LChild = &nodeD;
  46. nodeC.RChild = &nodeE;
  47. nodeF.RChild = &nodeG;
  48. nodeG.LChild = &nodeH;
  49. //1、求树中的叶子的数量
  50. int num = 0;
  51. calculateLeafNum(&nodeA ,&num);
  52. printf ("LeafNum=%d\n",num);
  53. //2、求树的高度、深度
  54. int height = getTreeHeight(&nodeA);
  55. printf ("tree height is=%d\n",height);
  56. }
  57. int main () {
  58. test01();
  59. return 0;
  60. }

5、二叉树的拷贝

  1. struct BinaryNode * copyBinaryTree(struct BinaryNode* root){
  2. if(root == NULL){
  3. return NULL;
  4. }
  5. //先拷贝 左子树
  6. struct BinaryNode * LChild = copyBinaryTree (root->LChild);
  7. //再拷贝 右子树
  8. struct BinaryNode * RChild = copyBinaryTree (root->RChild);
  9. //创建新的节点
  10. struct BinaryNode * newNode = malloc(sizeof (struct BinaryNode ));
  11. newNode->LChild = LChild;
  12. newNode->RChild = RChild;
  13. //返回给新用户
  14. newNode->ch = root->ch;
  15. return newNode;
  16. }
  1. //遍历树
  2. void showBinaryTree(struct BinaryNode * root){
  3. if(root == NULL){
  4. return;
  5. }
  6. printf ("%c",root->ch);
  7. showBinaryTree (root->LChild);
  8. showBinaryTree (root->RChild);
  9. }

全部测试代码

  1. #include <stdio.h>
  2. #include "string.h"
  3. #include "stdlib.h"
  4. struct BinaryNode{
  5. char ch;//数据域
  6. struct BinaryNode * LChild;//左孩子节点
  7. struct BinaryNode * RChild;//右孩子节点
  8. };
  9. //统计叶子数量的函数
  10. void calculateLeafNum(struct BinaryNode * root, int * num){
  11. //递归的结束条件
  12. if(root == NULL){
  13. return;
  14. }
  15. //判断当前节点的左孩子和右孩子是否为空。如果为空数字就累加
  16. if(root->LChild == NULL && root->RChild == NULL){
  17. (*num)++;
  18. }
  19. calculateLeafNum (root->LChild,num);
  20. calculateLeafNum (root->RChild,num);
  21. }
  22. int getTreeHeight(struct BinaryNode* root){
  23. if(root == NULL){
  24. return 0;
  25. }
  26. //求出左子树的高度
  27. int LHeight = getTreeHeight(root->LChild);
  28. //计算右子树的高度
  29. int RHeight = getTreeHeight(root->RChild);
  30. //取左子树和右子树,中最大的值 +1
  31. int height = LHeight > RHeight ? LHeight + 1 : RHeight + 1;
  32. return height;
  33. }
  34. struct BinaryNode * copyBinaryTree(struct BinaryNode* root){
  35. if(root == NULL){
  36. return NULL;
  37. }
  38. //先拷贝 左子树
  39. struct BinaryNode * LChild = copyBinaryTree (root->LChild);
  40. //再拷贝 右子树
  41. struct BinaryNode * RChild = copyBinaryTree (root->RChild);
  42. //创建新的节点
  43. struct BinaryNode * newNode = malloc(sizeof (struct BinaryNode ));
  44. newNode->LChild = LChild;
  45. newNode->RChild = RChild;
  46. //返回给新用户
  47. newNode->ch = root->ch;
  48. return newNode;
  49. }
  50. //遍历树
  51. void showBinaryTree(struct BinaryNode * root){
  52. if(root == NULL){
  53. return;
  54. }
  55. printf ("%c",root->ch);
  56. showBinaryTree (root->LChild);
  57. showBinaryTree (root->RChild);
  58. }
  59. void test01(){
  60. struct BinaryNode nodeA = {'A',NULL,NULL};
  61. struct BinaryNode nodeB = {'B',NULL,NULL};
  62. struct BinaryNode nodeC = {'C',NULL,NULL};
  63. struct BinaryNode nodeD = {'D',NULL,NULL};
  64. struct BinaryNode nodeE = {'E',NULL,NULL};
  65. struct BinaryNode nodeF = {'F',NULL,NULL};
  66. struct BinaryNode nodeG = {'G',NULL,NULL};
  67. struct BinaryNode nodeH = {'H',NULL,NULL};
  68. //建立结点之间的关系
  69. nodeA.LChild = &nodeB;
  70. nodeA.RChild = &nodeF;
  71. nodeB.RChild = &nodeC;
  72. nodeC.LChild = &nodeD;
  73. nodeC.RChild = &nodeE;
  74. nodeF.RChild = &nodeG;
  75. nodeG.LChild = &nodeH;
  76. printf ("show BinaryTree\n");
  77. showBinaryTree(&nodeA);
  78. //1、求树中的叶子的数量
  79. int num = 0;
  80. calculateLeafNum(&nodeA ,&num);
  81. printf ("\nLeafNum=%d\n",num);
  82. //2、求树的高度、深度
  83. int height = getTreeHeight(&nodeA);
  84. printf ("tree height is=%d\n",height);
  85. //3、拷贝二叉树
  86. struct BinaryNode * newTree = copyBinaryTree(&nodeA);
  87. printf ("show Copy BinaryTree\n");
  88. showBinaryTree(newTree);
  89. }
  90. int main () {
  91. test01();
  92. return 0;
  93. }

运行结果

6、二叉树的释放

  1. //释放二叉树freeTree
  2. void freeTree(struct BinaryNode * root )
  3. {
  4. if(root == NULL){
  5. return;
  6. }
  7. //先释放左子树
  8. freeTree (root->LChild);
  9. //再释放右子树
  10. freeTree (root->RChild);
  11. printf ("%c __is free\n",root->ch);
  12. //释放根节点
  13. free(root);
  14. }

运行测试所有代码

  1. #include <stdio.h>
  2. #include "string.h"
  3. #include "stdlib.h"
  4. struct BinaryNode{
  5. char ch;//数据域
  6. struct BinaryNode * LChild;//左孩子节点
  7. struct BinaryNode * RChild;//右孩子节点
  8. };
  9. //统计叶子数量的函数
  10. void calculateLeafNum(struct BinaryNode * root, int * num){
  11. //递归的结束条件
  12. if(root == NULL){
  13. return;
  14. }
  15. //判断当前节点的左孩子和右孩子是否为空。如果为空数字就累加
  16. if(root->LChild == NULL && root->RChild == NULL){
  17. (*num)++;
  18. }
  19. calculateLeafNum (root->LChild,num);
  20. calculateLeafNum (root->RChild,num);
  21. }
  22. int getTreeHeight(struct BinaryNode* root){
  23. if(root == NULL){
  24. return 0;
  25. }
  26. //求出左子树的高度
  27. int LHeight = getTreeHeight(root->LChild);
  28. //计算右子树的高度
  29. int RHeight = getTreeHeight(root->RChild);
  30. //取左子树和右子树,中最大的值 +1
  31. int height = LHeight > RHeight ? LHeight + 1 : RHeight + 1;
  32. return height;
  33. }
  34. struct BinaryNode * copyBinaryTree(struct BinaryNode* root){
  35. if(root == NULL){
  36. return NULL;
  37. }
  38. //先拷贝 左子树
  39. struct BinaryNode * LChild = copyBinaryTree (root->LChild);
  40. //再拷贝 右子树
  41. struct BinaryNode * RChild = copyBinaryTree (root->RChild);
  42. //创建新的节点
  43. struct BinaryNode * newNode = malloc(sizeof (struct BinaryNode ));
  44. newNode->LChild = LChild;
  45. newNode->RChild = RChild;
  46. //返回给新用户
  47. newNode->ch = root->ch;
  48. return newNode;
  49. }
  50. //遍历树
  51. void showBinaryTree(struct BinaryNode * root){
  52. if(root == NULL){
  53. return;
  54. }
  55. printf ("%c",root->ch);
  56. showBinaryTree (root->LChild);
  57. showBinaryTree (root->RChild);
  58. }
  59. //释放二叉树freeTree
  60. void freeTree(struct BinaryNode * root )
  61. {
  62. if(root == NULL){
  63. return;
  64. }
  65. //先释放左子树
  66. freeTree (root->LChild);
  67. //再释放右子树
  68. freeTree (root->RChild);
  69. printf ("%c __is free\n",root->ch);
  70. //释放根节点
  71. free(root);
  72. }
  73. void test01(){
  74. struct BinaryNode nodeA = {'A',NULL,NULL};
  75. struct BinaryNode nodeB = {'B',NULL,NULL};
  76. struct BinaryNode nodeC = {'C',NULL,NULL};
  77. struct BinaryNode nodeD = {'D',NULL,NULL};
  78. struct BinaryNode nodeE = {'E',NULL,NULL};
  79. struct BinaryNode nodeF = {'F',NULL,NULL};
  80. struct BinaryNode nodeG = {'G',NULL,NULL};
  81. struct BinaryNode nodeH = {'H',NULL,NULL};
  82. //建立结点之间的关系
  83. nodeA.LChild = &nodeB;
  84. nodeA.RChild = &nodeF;
  85. nodeB.RChild = &nodeC;
  86. nodeC.LChild = &nodeD;
  87. nodeC.RChild = &nodeE;
  88. nodeF.RChild = &nodeG;
  89. nodeG.LChild = &nodeH;
  90. printf ("show BinaryTree\n");
  91. showBinaryTree(&nodeA);
  92. //1、求树中的叶子的数量
  93. int num = 0;
  94. calculateLeafNum(&nodeA ,&num);
  95. printf ("\nLeafNum=%d\n",num);
  96. //2、求树的高度、深度
  97. int height = getTreeHeight(&nodeA);
  98. printf ("tree height is=%d\n",height);
  99. //3、拷贝二叉树
  100. struct BinaryNode * newTree = copyBinaryTree(&nodeA);
  101. printf ("show Copy BinaryTree\n");
  102. showBinaryTree(newTree);
  103. //4、释放二叉树
  104. freeTree(newTree);
  105. }
  106. int main () {
  107. test01();
  108. return 0;
  109. }

相关文章

最新文章

更多