• 面试算法 二叉树的遍历,方法 :线索二叉树 ( morris ) ,前序遍历: 中序遍历: 后序遍历


    1.题目:二叉树遍历
    前序遍历:根左右
    中序遍历:左根右
    后序遍历:左右根
    层序遍历:从上往下、从左往右

     算法: morris遍历


    2.算法:

    morris算法:


    3.算法思想: (这东西讲不清    bibi  看视频!!!)

    前序遍历 
    总结: 1.首先遇到节点左边是 NULL  打印自己 ,遍历自己的右节点  
         2.遇到右节点为空 ,打印数据 节点数据    还有 就是建立线索二叉树,继续遍历自己的左节点, 
             3.遇到线索二叉树,消除线索二叉树 ,遍历自己的 右节点 
     

    中序遍历 
    总结: 1.首先到达最左边的时候 需要打印数据
           2.断开线索连接的时候 打印数据 
           3.节点的最左边为 NULL  打印当前节点的数据 
     

    后序遍历
    总结: 断开线索二叉树的时候,链表反转,打印数据 


    4.代码:

    1. /*************************************************
    2. 作者:She001
    3. 时间:2022/9/31
    4. 题目:二叉树遍历
    5. 前序遍历:根左右
    6. 中序遍历:左根右
    7. 后序遍历:左右根
    8. 算法 : morris遍历(线索二叉树)
    9. ***************************************************/
    10. #include<bits/stdc++.h>
    11. using namespace std;
    12. typedef struct student
    13. {
    14. int a;
    15. struct student * left;
    16. struct student * right;
    17. int shendu;//树的深度
    18. }node; //指针类型的
    19. /*//二叉树模型
    20. a1
    21. a2 a3
    22. a4 a5 a6 a7
    23. a8
    24. a9
    25. */
    26. ///
    27. //遍历的方法实现
    28. /*
    29. 前序遍历:根左右
    30. 中序遍历:左根右
    31. 后序遍历:左右根
    32. 层序遍历:从上往下、从左往右
    33. */
    34. // 手写方法1 的 前序遍历 过程
    35. /*
    36. 1.开始 cur== a1 ,定义了 mostright=NULL
    37. 2.mostright = cur->left =a1->lift = a2 ;|| mostright 进入循环 -> 一直到 mostright= a5 ,
    38. 3. 退出 while 循环 进入判断 判读条件成功的为 mostright == NULL ,所以我们建立 线索二叉树 ====|||a5 ->right =a1;||||====
    39. 打印数据 输出数据 cur ->a = 打印 a1->a ; cur=cur->left= a2; continue;
    40. 4.这次从 a2 开始 我们开始
    41. 5. mostright = cur->lift = a2->lift =a4;
    42. 6.不能进入while 循环 ,因为 s4->right =NULL ;
    43. 7. 进入if 判断 所以 =====||||a4 -> right = a2;|||||=====
    44. 输出数据 cur->a = 输出数据 a2-> a ; cur= cur->left =a4 continue;
    45. 8.这次从 a4 开始
    46. 9.开始 mostright= cur->left =a4 ->left =NULL
    47. 10. 进入 mostright ==NULL 的判断 判断不成立 所以进入 else 的里面 输出数据 cur ->a = a4->a 然后我们的出来最后有一个 cur =cur -> right = a4->right ; cur=a2
    48. 11. cur=a2 mostright = a2->left = a4 ; 进入 while 循环 退出循环,, 因为 mostright ->right=cur ; 删除 线索二叉树 cur = cur->right = a2->right= a5;
    49. 12. 这时候 从 cur = a5 开始
    50. 13. mostright =cur ->left =a5->left =NULL
    51. 14.mostright =NULL if 判断 , mostright =NULL 所以我们进入 else 空间 ,所以执行 打印数据,cur ->a = a5->a ,
    52. 15.cur=cur->right = a5-> right = a1;
    53. 16.mostright= cur->left =a2 ; 进入循环 , 退出循环因为 mostright->right = a2-> right=a5 , mostright->right=a5->right =a1 , mostright ==cur 这个原因退出循环
    54. 17.进入判断 因为 mostright == cur 所以 删除 线索二叉树的连接! cur = cur -> right = a1 -> a3;
    55. 18. mostright =cur->left =a3->left = a6 进入 循环出来 判断 mostright -> right =NULL ========|||||||| a6 ->right = a3;
    56. 打印 cur-> a = a3->a ; cur=cur ->left = a3->left =a6;
    57. 19. mostright = cur-> left = a6->left = a8 ; mostright进入循环 ,直到 a9 的时候停止。 ======||||||||||||a9->right =a6;
    58. 打印cur ->a =a6 ->a ; cur= cur->left = a6->left = a8 ;
    59. 20.mostright =cur ->left =NULL 打印 a8->a cur=cur->right = a9;
    60. 21. mostright= a9->left = NULL; 所以 停止,打印 cur-> a = a9->a; cur =a9 ->right = a6 ;
    61. 21 mostright= cur-> left =a8 ; a8->right = a9 a9 ->right =a6 mostright== cur 循环停止 所以消除线索二叉树 , cur = cur->right = a6-> right = a3;
    62. 22.mostright = cur->left = a3->left=a6; mostright->right ===cur 循环结束 所以消除线索二叉树 , cur = cur -> right = a7;
    63. 23. mostright = a7->right =NULL ; 建立线索二叉树, a7->right = a7; , 打印 a7 ; cur= cur->left = NULL ,
    64. 24.if 判断 cur == NULl 退出外部的大循环!
    65. */
    66. /*
    67. 前序遍历
    68. 总结: 1.首先遇到节点左边是 NULL 打印自己 ,遍历自己的右节点
    69. 2.遇到右节点为空 ,打印数据 节点数据 还有 就是建立线索二叉树,继续遍历自己的左节点,
    70. 3.遇到线索二叉树,消除线索二叉树 ,遍历自己的 右节点
    71. */
    72. void fangfa_1(node * cur)//前序遍历
    73. {
    74. if(cur == NULL)
    75. {
    76. return ;
    77. }
    78. node * mostright = NULL; //寻找最左边子树的 最靠右的叶子节点 标记位
    79. while(cur !=NULL)
    80. {
    81. mostright=cur->left;//寻找开始,从当前节点的下一个左边节点 ,开始寻找,寻找当前节点左子树的最靠右的叶子节点 (假如没有就 没有)
    82. if(mostright !=NULL)
    83. {
    84. while(mostright->right!=NULL && mostright->right!=cur)//一直找,停止的条件,第一个是当前节点的右节点为 NULL , 第二个是 当前线索二叉树已经建立,
    85. {
    86. mostright=mostright->right;//往右走
    87. }
    88. if(mostright->right==NULL)//找到了 cur 节点的子树的最右边节点 ,建立线索二叉树
    89. {
    90. mostright->right=cur; //我们建立线索二叉树 实现子树 最右边的节点 连接 当前的节点
    91. //因为 这个是 前序的遍历,所以我们到了 节点 就打印
    92. cout<<cur->a<<" ";
    93. cur=cur->left;//寻找当前节点的左边节点的线索二叉树
    94. continue; //结束,再次循环 //防止与下一步冲突
    95. }
    96. else//已经含有线索二叉树,我们需要删除节点,
    97. {
    98. mostright->right=NULL;//删除含有线索的叶子节点 的连接
    99. }
    100. }
    101. else//当我们的 mostright==NULL 的时候我们需要打印数值 // 因为此时是二叉树的最左边的节点 ,打印当前的节点的值
    102. {
    103. cout<<cur->a<<" "; //打印数值
    104. }
    105. cur=cur->right;
    106. }
    107. }
    108. /*
    109. 中序遍历
    110. 总结: 1.首先到达最左边的时候 需要打印数据
    111. 2.断开线索连接的时候 打印数据
    112. 3.节点的最左边为 NULL 打印当前节点的数据
    113. */
    114. void fangfa_2(node * cur)//中序遍历
    115. {
    116. if(cur == NULL)
    117. {
    118. return ;
    119. }
    120. node * mostright = NULL; //寻找最左边子树的 最靠右的叶子节点 标记位
    121. while(cur !=NULL)
    122. {
    123. mostright=cur->left;//寻找开始,从当前节点的下一个左边节点 ,开始寻找,寻找当前节点左子树的最靠右的叶子节点 (假如没有就 没有)
    124. if(mostright !=NULL)
    125. {
    126. while(mostright->right!=NULL && mostright->right!=cur)//一直找,停止的条件,第一个是当前节点的右节点为 NULL , 第二个是 当前线索二叉树已经建立,
    127. {
    128. mostright=mostright->right;//往右走
    129. }
    130. if(mostright->right==NULL)//找到了 cur 节点的子树的最右边节点 ,建立线索二叉树
    131. {
    132. mostright->right=cur; //我们建立线索二叉树 实现子树 最右边的节点 连接 当前的节点
    133. cur=cur->left;//寻找当前节点的左边节点的线索二叉树
    134. continue; //结束,再次循环 //防止与下一步冲突
    135. }
    136. else//已经含有线索二叉树,我们需要删除节点,
    137. {
    138. mostright->right=NULL;//删除含有线索的叶子节点 的连接
    139. }
    140. }
    141. else//当我们的 mostright==NULL 的时候我们需要打印数值 // 因为此时是二叉树的最左边的节点 ,打印当前的节点的值
    142. {
    143. }
    144. cout<<cur->a<<" "; //打印数值
    145. cur=cur->right;
    146. }
    147. }
    148. /*
    149. 后序遍历
    150. 总结: 断开线索二叉树的时候,链表反转,打印数据
    151. */
    152. node* reverse(node* head)//链表反转
    153. {
    154. node* prev =NULL;
    155. node* curr;
    156. node* next;
    157. curr=head;
    158. while(curr!=NULL)
    159. {
    160. next=curr->right;
    161. curr->right=prev;
    162. prev=curr;
    163. curr=next;
    164. }
    165. return prev;
    166. }
    167. void printnode(node *head)//打印数据 ,步骤,链表反转,打印数据,还原链表,保持二叉树的完整性
    168. {
    169. node *hh = reverse(head);//第一反过来
    170. node * ww=hh;//保存开头的节点
    171. while(hh!=NULL)//打印数据
    172. {
    173. cout<<hh->a<<" ";
    174. hh=hh->right;
    175. }
    176. reverse(ww); //还原
    177. }
    178. void fangfa_3(node * cur)//中序遍历
    179. {
    180. if(cur == NULL)
    181. {
    182. return ;
    183. }
    184. node * mostright = NULL; //寻找最左边子树的 最靠右的叶子节点 标记位
    185. node * jj=cur;
    186. while(cur !=NULL)
    187. {
    188. mostright=cur->left;//寻找开始,从当前节点的下一个左边节点 ,开始寻找,寻找当前节点左子树的最靠右的叶子节点 (假如没有就 没有)
    189. if(mostright !=NULL)
    190. {
    191. while(mostright->right!=NULL && mostright->right!=cur)//一直找,停止的条件,第一个是当前节点的右节点为 NULL , 第二个是 当前线索二叉树已经建立,
    192. {
    193. mostright=mostright->right;//往右走
    194. }
    195. if(mostright->right==NULL)//找到了 cur 节点的子树的最右边节点 ,建立线索二叉树
    196. {
    197. mostright->right=cur; //我们建立线索二叉树 实现子树 最右边的节点 连接 当前的节点
    198. cur=cur->left;//寻找当前节点的左边节点的线索二叉树
    199. continue; //结束,再次循环 //防止与下一步冲突
    200. }
    201. else//已经含有线索二叉树,我们需要删除节点,
    202. {
    203. mostright->right=NULL;//删除含有线索的叶子节点 的连接
    204. printnode(cur->left);
    205. }
    206. }
    207. cur=cur->right;
    208. }
    209. printnode(jj);
    210. }
    211. int main()
    212. {
    213. //数据初始化,建立树
    214. struct student *a1 =new struct student;
    215. struct student *a2 =new struct student;
    216. struct student *a3 =new struct student;
    217. struct student *a4 =new struct student;
    218. struct student *a5 =new struct student;
    219. struct student *a6 =new struct student;
    220. struct student *a7 =new struct student;
    221. struct student *a8 =new struct student;
    222. struct student *a9 =new struct student;
    223. //数值的赋值
    224. a1->a=1;
    225. a2->a=2;
    226. a3->a=3;
    227. a4->a=4;
    228. a5->a=5;
    229. a6->a=6;
    230. a7->a=7;
    231. a8->a=8;
    232. a9->a=9;
    233. //节点的连接
    234. a1->left=a2;
    235. a1->right=a3;
    236. a2->left=a4;
    237. a2->right=a5;
    238. a3->left=a6;
    239. a3->right=a7;
    240. a6->left=a8;
    241. a8->right=a9;
    242. //节点为空的设置
    243. a4->left=NULL;
    244. a4->right=NULL;
    245. a5->left=NULL;
    246. a5->right=NULL;
    247. a8->left=NULL;
    248. a9->left=NULL;
    249. a9->right=NULL;
    250. a6->right=NULL;
    251. a7->left=NULL;
    252. a7->right=NULL;
    253. //打印前序遍历
    254. cout<<"前序遍历: ";
    255. fangfa_1(a1);
    256. cout<<endl;
    257. //打印中序遍历
    258. cout<<"中序遍历: ";
    259. fangfa_2(a1);
    260. cout<<endl;
    261. //打印后序遍历
    262. cout<<"后序遍历 : ";
    263. fangfa_3(a1);
    264. cout<<endl;
    265. //释放空间
    266. delete a1;
    267. delete a2;
    268. delete a3;
    269. delete a4;
    270. delete a5;
    271. delete a6;
    272. delete a7;
    273. delete a8;
    274. delete a9;
    275. return 0;
    276. }

     5.线索二叉树的解释

    线索二叉树是链表表示的树,它是利用了二叉树未被使用的 n + 1个闲置的指针构成的树;
    根据二叉树的三种遍历方式构成了三种不同的线索二叉树;
    二叉树的遍历只能从根结点开始依次遍历,而构建了线索二叉树后,就可以从二叉树中任何一个结点进行遍历,这就是线索化最大的意义了;
    实际上线索二叉树的应用面是很窄的,但是学习它最重要的意义还是理解它的这种思想;
    就是将闲置的空间充分利用起来,这应该是最重要的意义了;

    本质:

    二叉树的遍历本质上是将一个复杂的非线性结构转换为线性结构,使每个结点都有了唯一前驱和后继(第一个结点无前驱,最后一个结点无后继)。对于二叉树的一个结点,查找其左右子女是方便的,其前驱后继只有在遍历中得到。为了容易找到前驱和后继,有两种方法。一是在结点结构中增加向前和向后的指针,这种方法增加了存储开销,不可取;二是利用二叉树的空链指针。

    优势

    (1)利用线索二叉树进行中序遍历时,不必采用堆栈处理,速度较一般二叉树的遍历速度快,且节约存储空间。

    (2)任意一个结点都能直接找到它的前驱和后继结点。 

    不足

    (1)结点的插入和删除麻烦,且速度也较慢。

    (2)线索子树不能共用。 

    密语:

    其实无论是什么样的序列化,只需要记得下面这三句话:

    • 如果结点有左孩子:那么Lchild指向他的左孩子,否则指向遍历序列中他的前驱结点。
    • 如果结点有右孩子:那么Rchild依然指向他的左孩子,否则指向遍历序列的后继节点。
    • 前驱或者后驱没有,就为NULL。
  • 相关阅读:
    Hystrix 服务熔断
    java的JSR、JCP访问地址
    Flutter快学快用02 事件循环:Flutter 中代码是如何执行和运行的
    大数据生态圈完整知识体系
    abc 137 Count 1‘s 【经典思维】
    html5学习笔记19-SSE服务器发送事件(Server-Sent Events)
    LabVIEW挖坑指南
    2022年最新Android面试题整理,全网都在看,史上最全面试攻略
    【HDR】Deep high dynamic range imaging of dynamic scenes
    逐字稿 | 8 视频理解论文串讲(上)【论文精读】
  • 原文地址:https://blog.csdn.net/she666666/article/details/126664383