• 王道书 P149 T5(求树高) + 拓展(求某点的层次/深度)(二叉树链式存储实现)


    1. /**
    2. * 用二叉树链式存储实现 王道 P149 T5(求树高) + 拓展(求某点的层次/深度、求树的宽度)
    3. *
    4. *
    5. * ①算法思想
    6. * 注:①是递归求树高(两种方法实现)
    7. * ②是非递归求树高(非递归后序遍历拿来改一下)
    8. * ③是非递归求层次/深度(非递归后序遍历或②拿来改一下)
    9. * ④是递归求层次/深度(递归的先序、中序、后序遍历都可以拿来改一下)
    10. * ⑤是递归方式求树高(递归的先序、中序、后序遍历或②都可以拿来改一下)
    11. * ⑥是非递归求树的宽度(层次遍历拿来改一下)
    12. * ⑦是非递归求树高(层次遍历或⑥拿来改一下)
    13. * 对于① 递归求树高(平时经常用的)
    14. * 首先,如果树是空的话,树高就是0;
    15. * 当树不为空时,高度就是左子树和右子树中较高的那一个的高度再加上根节点自己的高度。
    16. * 此题就转化成了求左右子树高度的问题。
    17. * 对于② 非递归求树高
    18. * 二叉树的高度 = 从根节点到叶子节点的路径长度之和的最大值 + 1,把非递归后序遍历拿来改一下(注意不要着急出栈那一点)。
    19. * 对于③ 非递归求层次/深度
    20. * 求某点的层次和②是有相似之处的,把②改一下即可(注意不要着急出栈那一点)。
    21. * 对于④ 递归求层次/深度
    22. * 递归的先序、中序、后序遍历都可以拿来改一下。
    23. * 对于⑤ 递归求树高
    24. * 其实就是求最大深度,递归的先序、中序、后序遍历或②都可以拿来改一下。
    25. * 对于⑥ 非递归求树宽
    26. * 从层次遍历的角度思考。
    27. * 对于⑦ 非递归求树高
    28. * 从层次遍历的角度或⑥的角度思考。
    29. *
    30. *
    31. * ②算法设计
    32. */
    33. #include <stdio.h>
    34. #include <iostream>
    35. #define MaxSize 100
    36. typedef struct BiTreeNode{
    37. int data;
    38. BiTreeNode *lchild,*rchild;
    39. }BiTreeNode,*BiTree;
    40. //P149 T5
    41. //①递归算法直接求解二叉树高度(可以动手画个栈一层一层压栈再return弹栈理解一下)
    42. //1
    43. int GetHeightNR(BiTree T){
    44. if(T == NULL)
    45. return 0;
    46. int left = GetHeightNR(T -> lchild);
    47. int right = GetHeightNR(T -> rchild);
    48. return left > right ? left + 1 : right + 1;
    49. }
    50. //2
    51. int height(BiTree T){
    52. if(T == NULL)
    53. return 0;
    54. if(T -> lchild)
    55. return 1 + height(T -> lchild);
    56. if(T -> rchild)
    57. return 1 + height(T -> rchild);
    58. }
    59. //②非递归算法求解二叉树高度---通过求根节点到叶子结点的路径长度之和最大的值+1的方式求解二叉树高度
    60. int GetHeightByPostNR(BiTree T){
    61. BiTree stack[MaxSize],p = T;
    62. int top = -1,tag[MaxSize] = {0},max = -1;//max用来记录高度
    63. while(p || top != -1){
    64. if(p){
    65. stack[++top] = p;
    66. tag[top] = 1;
    67. p = p -> lchild;
    68. }else{
    69. if(tag[top] == 1){
    70. tag[top] = 2;
    71. p = stack[top];//找到栈顶元素,这样才能接着往下找
    72. p = p -> rchild;
    73. }else{//说明是狭义的“叶子节点”了
    74. p = stack[top];//访问这个点的时候先不急着出栈,因为如果直接出栈的话,高度就有损失了
    75. if(p -> lchild == NULL && p -> rchild == NULL){//说明是叶子节点
    76. if(top + 1 > max)//top是从-1开始的,或者说top是数组的下标,所以要+1才是路径的长度
    77. //注意这个top是一直在变化的,所以每遇到一个叶子节点,就要来比较一下,这样才能找到路径最长的叶子节点。
    78. max = top + 1;
    79. }
    80. top--;
    81. p = NULL;
    82. }
    83. }
    84. }
    85. return max;
    86. }
    87. //③使用非递归方式通过②可以拓展到求出某个点所在的层次/深度
    88. int GetLevelByPostNR(BiTree T,int data){
    89. BiTree stack[MaxSize],p = T;
    90. int top = -1,tag[MaxSize] = {0};
    91. while(p || top != -1){
    92. if(p){
    93. stack[++top] = p;
    94. tag[top] = 1;
    95. p = p -> lchild;
    96. }else{
    97. if(tag[top] == 1){
    98. tag[top] = 2;
    99. p = stack[top];//找到栈顶元素,这样才能接着往下找
    100. p = p -> rchild;
    101. }else{//说明是叶子节点了
    102. p = stack[top];//访问这个点的时候先不急着出栈,因为如果直接出栈的话,高度就有损失了
    103. if(p -> data == data){
    104. return top + 1;//在非递归后序遍历中,每个点其实都是某种意义上的叶子节点,每个要弹出的元素都会经历这一步,
    105. //在经历这一步时,都是某种意义上的叶子节点,而此时就和②相似了,
    106. //根节点到叶子结点的路径长度+1就是此节点的高度,此时要弹出的这个点就相当于叶子节点,
    107. //所以可以用和②同样的方法,算此节点的层次就是路径长度+1
    108. //而路径长度就是前面的祖先数量,也就是在压在栈里还没有弹出的元素数量。
    109. //所以就是top+1
    110. }
    111. top--;
    112. p = NULL;
    113. }
    114. }
    115. }
    116. return -1;//说明没找到这个点
    117. }
    118. //④递归方式求某点的层次/深度
    119. //刚开始传T,14,dataDeep
    120. void GetDeep(BiTree T,int deep,int data,int &dataDeep){//GetDeep中的Deep和level是一个意思,dataDeep是这个data的深度
    121. if(T != NULL){
    122. if(T -> data == data){
    123. dataDeep = deep;//用dataDeep把deep带回
    124. }
    125. GetDeep(T -> lchild,deep + 1,data,dataDeep);
    126. GetDeep(T -> rchild,deep + 1,data,dataDeep);
    127. }
    128. }
    129. //关于④的测试
    130. int main(){
    131. BiTree T = CreatBiTree();
    132. int dataDeep = -1;
    133. GetDeep(T,1,4,dataDeep);
    134. printf("%d ",dataDeep);
    135. return 0;
    136. }
    137. //⑤递归方式求树高(高度其实就是最大深度)
    138. //刚开始传T,1,0
    139. void GetHeightByDeep(BiTree T,int deep,int &height){//用height带回
    140. if(T != NULL){
    141. if(T -> lchild == NULL && T -> rchild == NULL){//如果是叶子节点
    142. if(deep > height)
    143. height = deep;
    144. }
    145. GetHeightByDeep(T -> lchild,deep + 1,height);
    146. GetHeightByDeep(T -> rchild,deep + 1,height);
    147. }
    148. }
    149. //关于⑤的测试
    150. int main(){
    151. BiTree T = CreatBiTree();
    152. int height = 0;
    153. GetHeightByDeep(T,1,height);
    154. printf("%d ",height);
    155. return 0;
    156. }
    157. //⑥非递归方式求树宽(树宽:节点个数最多的那一层的节点个数)
    158. int GetWidthByLevel(BiTree T){
    159. if(T == NULL)
    160. return 0;
    161. if(T -> lchild == NULL && T -> rchild ==NULL)
    162. return 1;
    163. BiTree Queue[MaxSize];//Queue用来存放树的地址
    164. BiTree p = T;
    165. int front = -1, rear = -1;
    166. int last = 0,width = 0;//last用来标记每次上一层rear在该层末尾的值,刚开始有一个元素,rear从-1变成0
    167. Queue[++rear] = p;//入队
    168. while(front != rear){
    169. p = Queue[++front];
    170. if(p -> lchild != NULL)
    171. Queue[++rear] = p -> lchild;
    172. if(p -> rchild != NULL)
    173. Queue[++rear] = p -> rchild;
    174. //判断
    175. if(front == last){//当front = 上一层rear末尾的值时,说明这一层结束了,下一层所有的元素已经入队了,rear已经指向了front下一层的末尾的值。
    176. if(rear - front > width){
    177. width = rear - front;
    178. }
    179. last = rear;//last重新等于新的一层的rear的末尾的值,方便接下来的front和last的比较
    180. }
    181. }
    182. return width;
    183. }
    184. //⑦非递归方式求树高
    185. int GetHeightByLevel(BiTree T){
    186. if(T == NULL)
    187. return 0;
    188. if(T -> lchild == NULL && T -> rchild ==NULL)
    189. return 1;
    190. BiTree Queue[MaxSize];//Queue用来存放树的地址
    191. BiTree p = T;
    192. int front = -1, rear = -1;
    193. int last = 0,level = 0;//last用来标记每次上一层rear在该层末尾的值,刚开始有一个元素,rear从-1变成0
    194. Queue[++rear] = p;//入队
    195. while(front != rear){
    196. p = Queue[++front];
    197. if(p -> lchild != NULL)
    198. Queue[++rear] = p -> lchild;
    199. if(p -> rchild != NULL)
    200. Queue[++rear] = p -> rchild;
    201. //判断
    202. if(front == last){//当front = 上一层rear末尾的值时,说明这一层结束了,
    203. // 如果有下一层的话,下一层所有的元素已经入队了,rear已经指向了front下一层的末尾的值。
    204. level++;
    205. last = rear;//last重新等于新的一层的rear的末尾的值,方便接下来的front和last的比较
    206. }
    207. }
    208. return level;
    209. }

  • 相关阅读:
    以创新赋能引领鸿蒙应用开发,凡泰极客亮相华为HDC2024
    Java_接口
    JavaWeb在线问题.系列博文入口
    华纳云:tomcat高并发阻塞问题怎么解决
    ChatGPT 入门指南:与 AI 进行愉快互动的秘诀大揭秘!
    从零开始写一个PHP开发框架websocket框架
    基于SSM实现的社区论坛系统(附PPT、设计文档)
    em与rem的区别
    支持语音与视频即时通讯项目杂记(一)
    LeetCode-538. Convert BST to Greater Tree [C++][Java]
  • 原文地址:https://blog.csdn.net/shengruyu/article/details/126588409