当前位置:   article > 正文

【数据结构】二叉树的实现

【数据结构】二叉树的实现

如有不懂的地方,可翻阅我之前文章哦!

                 个人主页小八哥向前冲~

                  所属专栏数据结构【c语言】

目录

前言

二叉树的遍历

前序遍历

中序遍历

后序遍历

总结点数

二叉树的高度

第k层叶子数

查找x值

叶子总数

左(右)孩子数

树的销毁

总代码


前言

前一章我们学习了堆,并且了解了什么是树。简单来说,堆就是一个二叉树,现在我们来真正了解一下二叉树!

以这棵树为例:

我们如何用链式结构来表示一颗二叉树呢?不错,结构体

根据二叉树的节点特点,可以将每个部分分为左孩子节点,右孩子节点和根节点,于是我们可以这样来描述它:

  1. typedef struct TreeNode
  2. {
  3. struct TreeNode* left;//左孩子节点
  4. struct TreeNode* right;//右孩子节点
  5. TDatatype val;//节点数值
  6. }TNode;

现在我们手搓一个二叉树(上图为例),来进行深入研究!

  1. //创建节点
  2. TNode* BuyNode(TDatatype x)
  3. {
  4. TNode* node = (TNode*)malloc(sizeof(TNode));
  5. if (node == NULL)
  6. {
  7. perror("malloc failed!");
  8. return NULL;
  9. }
  10. node->left = node->right = NULL;
  11. node->val = x;
  12. return node;
  13. }
  14. //手动创建一个二叉树
  15. TNode* CreateTree()
  16. {
  17. TNode* node1 = BuyNode(1);
  18. TNode* node2 = BuyNode(2);
  19. TNode* node3 = BuyNode(3);
  20. TNode* node4 = BuyNode(4);
  21. TNode* node5 = BuyNode(5);
  22. TNode* node6 = BuyNode(6);
  23. node1->left = node2;
  24. node2->left = node3;
  25. node1->right = node4;
  26. node4->left = node5;
  27. node4->right = node6;
  28. return node1;
  29. }

二叉树的遍历

我们知道链表如何遍历,那么一颗链式树是怎么遍历的呢?

这里有三种遍历方法——前,中,后序遍历!

前序遍历

前序遍历是按照:根,左子树,右子树的方式层层遍历的

(上图为例)前序遍历结果为:1  2  3 NULL NULL NULL 4 5 NULL NULL 6 NULL NULL

代码:

  1. //前序遍历 根 左子树 右子树
  2. void Preoder(TNode* root)
  3. {
  4. if (root == NULL)
  5. {
  6. printf("N ");
  7. return;
  8. }
  9. printf("%d ", root->val);
  10. Preoder(root->left);
  11. Preoder(root->right);
  12. }

当根走完,再走左子树遍历,再走右子树遍历,直到全部走完!(递归方式走完)

中序遍历

中序遍历按照:左子树,根,右子树的的方式遍历

(上图为例)中序遍历结果:NULL 3 NULL 2 NULL 1 NULL 5  NULL 4 NULL 6  NULL 

代码:

  1. //中序遍历 左子树 根 右子树
  2. void Inoder(TNode* root)
  3. {
  4. if (root == NULL)
  5. {
  6. printf("N ");
  7. return;
  8. }
  9. Inoder(root->left);
  10. printf("%d ", root->val);
  11. Inoder(root->right);
  12. }

先走左子树遍历,再走根遍历,再走右子树遍历,直到全部递归走完!

后序遍历

后序遍历按照:左子树,右子树,根方式遍历。

(上图为例)后序遍历结果:NULL  NULL  3 NULL  2  NULL  NULL  5  NULL  NULL  6 4 1

 代码:

  1. //后序遍历 左子树 右子树 根
  2. void Afteroder(TNode* root)
  3. {
  4. if (root == NULL)
  5. {
  6. printf("N ");
  7. return;
  8. }
  9. Afteroder(root->left);
  10. Afteroder(root->right);
  11. printf("%d ", root->val);
  12. }

先走左子树遍历,再走右子树遍历,最后走根!直到递归走完!

总结点数

我们不难知道:总结点数==左子树节点数+右子树节点数+1(根本身)

如果根为空,节点数就是0

代码

  1. //节点数
  2. int TreeSize(TNode* root)
  3. {
  4. //每个部分可以看成:左子树+右子树+1(自身)
  5. return root == NULL ? 0 : TreeSize(root->left) +
  6. TreeSize(root->right) + 1;
  7. }

二叉树的高度

分析:树的高度==左右子树中高的那个子树的高度+1。

代码

  1. int HeightTree(TNode* root)
  2. {
  3. //高的子树+1就是高度
  4. if (root == NULL)
  5. return 0;
  6. int leftheight = HeightTree(root->left);
  7. int rightHeight = HeightTree(root->right);
  8. return leftheight > rightHeight ?
  9. leftheight + 1 : rightHeight + 1;
  10. }

第k层叶子数

分析:第k层叶子数==第k层的左子树的叶子数+第k层的右子树的叶子数

如果第k层的叶子为空,那就没有这个叶子!

代码

  1. //第k层树的节点数
  2. int LeafKSize(TNode* root, int k)
  3. {
  4. //第k层:左子树+右子树的叶子数
  5. if (root == NULL)
  6. return 0;
  7. if (k == 1)
  8. return 1;
  9. return LeafKSize(root->left, k - 1) + LeafKSize(root->right, k - 1);
  10. }

查找x值

思路:先找左子树,如果有返回,没有再去右子树查找,有的话返回,没有返回空

代码

  1. //查找值为x的节点
  2. TNode* TreeFind(TNode* root, TDatatype x)
  3. {
  4. if (root == NULL)
  5. return NULL;
  6. if (root->val == x)
  7. return root;
  8. TNode* node1 = TreeFind(root->left,x);
  9. //左子树没找到,就去右子树找
  10. if (node1)
  11. return node1;
  12. //在右子树找
  13. return TreeFind(root->right, x);
  14. }

叶子总数

思路叶子总数==左子树叶子总数+右子树叶子总数

我们要判断某个节点是不是叶子,这个节点的左右孩子是否都为NULL就行!

代码

  1. //叶子数
  2. int LeafSize(TNode* root)
  3. {
  4. if (root == NULL)
  5. return 0;
  6. if (root->left == NULL && root->right == NULL)
  7. return 1;
  8. return LeafSize(root->left) + LeafSize(root->right);
  9. }

左(右)孩子数

以统计左孩子数为例:

我们知道:左孩子数==左子树中的左孩子数+右子树中的左孩子数

思路

遍历左子树和右子树,如果有左孩子就记下来!

代码

  1. //左孩子数
  2. int LeftSize(TNode* root)
  3. {
  4. int count = 0;
  5. if (root == NULL)
  6. return 0;
  7. else
  8. {
  9. //如果有左孩子,数量就存起来
  10. if (root->left)
  11. count++;
  12. }
  13. //遍历一遍,最后再加总数
  14. return LeftSize(root->left) + LeftSize(root->right) + count;
  15. }

树的销毁

销毁树节点要注意一个点就是:需要先销毁左子树节点,再销毁右子树节点,最后销毁根节点

代码

  1. //二叉树的销毁
  2. void TreeDestroy(TNode* root)
  3. {
  4. if (root == NULL)
  5. return;
  6. TreeDestroy(root->left);
  7. TreeDestroy(root->right);
  8. free(root);
  9. }

总代码

Tree.h文件

  1. #include<stdio.h>
  2. #include<assert.h>
  3. #include<stdlib.h>
  4. typedef int TDatatype;
  5. typedef struct TreeNode
  6. {
  7. struct TreeNode* left;
  8. struct TreeNode* right;
  9. TDatatype val;
  10. }TNode;
  11. //创建节点
  12. TNode* BuyNode(TDatatype x);
  13. //创建一个二叉树
  14. TNode* CreateTree();
  15. //前序遍历 根 左子树 右子树
  16. void Preoder(TNode* root);
  17. //中序遍历 左子树 根 右子树
  18. void Inoder(TNode* root);
  19. //后序遍历 左子树 右子树 根
  20. void Afteroder(TNode* root);
  21. //节点数
  22. int TreeSize(TNode* root);
  23. //叶子数
  24. int LeafSize(TNode* root);
  25. //第k层树的节点数
  26. int LeafKSize(TNode* root,int k);
  27. //查找值为x的节点
  28. TNode* TreeFind(TNode* root, TDatatype x);
  29. //二叉树的销毁
  30. void TreeDestroy(TNode* root);
  31. //二叉树的高度
  32. int HeightTree(TNode* root);
  33. //左孩子数
  34. int LeftSize(TNode* root);

Tree.c文件

  1. //创建节点
  2. TNode* BuyNode(TDatatype x)
  3. {
  4. TNode* node = (TNode*)malloc(sizeof(TNode));
  5. if (node == NULL)
  6. {
  7. perror("malloc failed!");
  8. return NULL;
  9. }
  10. node->val = x;
  11. node->left = node->right = NULL;
  12. return node;
  13. }
  14. //创建一个二叉树
  15. TNode* CreateTree()
  16. {
  17. TNode* node1 = BuyNode(1);
  18. TNode* node2 = BuyNode(2);
  19. TNode* node3 = BuyNode(3);
  20. TNode* node4 = BuyNode(4);
  21. TNode* node5 = BuyNode(5);
  22. TNode* node6 = BuyNode(6);
  23. node1->left = node2;
  24. node1->right = node4;
  25. node2->left = node3;
  26. node4->left = node5;
  27. node4->right = node6;
  28. return node1;
  29. }
  30. //前序遍历 根 左子树 右子树
  31. void Preoder(TNode* root)
  32. {
  33. if (root == NULL)
  34. {
  35. printf("N ");
  36. return;
  37. }
  38. printf("%d ", root->val);
  39. Preoder(root->left);
  40. Preoder(root->right);
  41. }
  42. //中序遍历 左子树 根 右子树
  43. void Inoder(TNode* root)
  44. {
  45. if (root == NULL)
  46. {
  47. printf("N ");
  48. return;
  49. }
  50. Inoder(root->left);
  51. printf("%d ", root->val);
  52. Inoder(root->right);
  53. }
  54. //后序遍历 左子树 右子树 根
  55. void Afteroder(TNode* root)
  56. {
  57. if (root == NULL)
  58. {
  59. printf("N ");
  60. return;
  61. }
  62. Afteroder(root->left);
  63. Afteroder(root->right);
  64. printf("%d ", root->val);
  65. }
  66. //节点数
  67. int TreeSize(TNode* root)
  68. {
  69. //每个部分可以看成:左子树+右子树+1(自身)
  70. return root == NULL ? 0 : TreeSize(root->left) +
  71. TreeSize(root->right) + 1;
  72. }
  73. //叶子数
  74. int LeafSize(TNode* root)
  75. {
  76. if (root == NULL)
  77. return 0;
  78. if (root->left == NULL && root->right == NULL)
  79. return 1;
  80. return LeafSize(root->left) + LeafSize(root->right);
  81. }
  82. //第k层树的节点数
  83. int LeafKSize(TNode* root, int k)
  84. {
  85. //第k层:左子树+右子树的叶子数
  86. if (root == NULL)
  87. return 0;
  88. if (k == 1)
  89. return 1;
  90. return LeafKSize(root->left, k - 1) + LeafKSize(root->right, k - 1);
  91. }
  92. //查找值为x的节点
  93. TNode* TreeFind(TNode* root, TDatatype x)
  94. {
  95. if (root == NULL)
  96. return NULL;
  97. if (root->val == x)
  98. return root;
  99. TNode* node1 = TreeFind(root->left,x);
  100. //左子树没找到,就去右子树找
  101. if (node1)
  102. return node1;
  103. //在右子树找
  104. return TreeFind(root->right, x);
  105. }
  106. //二叉树的销毁
  107. void TreeDestroy(TNode* root)
  108. {
  109. if (root == NULL)
  110. return;
  111. TreeDestroy(root->left);
  112. TreeDestroy(root->right);
  113. free(root);
  114. }
  115. //二叉树的高度
  116. int HeightTree(TNode* root)
  117. {
  118. //高的子树+1就是高度
  119. if (root == NULL)
  120. return 0;
  121. int leftheight = HeightTree(root->left);
  122. int rightHeight = HeightTree(root->right);
  123. return leftheight > rightHeight ?
  124. leftheight + 1 : rightHeight + 1;
  125. }
  126. //左孩子数
  127. int LeftSize(TNode* root)
  128. {
  129. int count = 0;
  130. if (root == NULL)
  131. return 0;
  132. else
  133. {
  134. //如果有左孩子,数量就存起来
  135. if (root->left)
  136. count++;
  137. }
  138. //遍历一遍,最后再加总数
  139. return LeftSize(root->left) + LeftSize(root->right) + count;
  140. }

这期递归较多,比较难理解,有难度!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/668290
推荐阅读
相关标签
  

闽ICP备14008679号