Morris遍历

1.Morris遍历相较于深度优先遍历和宽度优先遍历的优势:

  其空间复杂度为O(1)

2.优化的思路核心:充分利用叶节点的空指针

3.算法思路:

* Morris遍历的实现细节:
* 假设来到当前节点cur,开始时cur为头节点的位置
* 1.如果cur没有左孩子,则cur向右移动(cur = cur.right)
* 2.如果cur有左孩子,找到左子树上的最右节点mostRight
* (1).如果mostRight的右指针指向空,则让其指向cur,然后cur向左移动(cur = cur.left)
* (2).如果mostRight的右指针指向cur,则让其指向null,然后cur向右移动(cur = cur.right)
* 3.cur为空时遍历停止
*
* Morris遍历的特点:
* 所有叶节点只被遍历到1次,非叶节点被遍历到2次

 

4.代码实现:

 1 public static void Morris(Node root) {
 2         if (root == null) {
 3             return;
 4         }
 5         Node cur = root;
 6         Node mostRight = null;
 7         while (cur != null) {//cur为空时遍历才结束
 8             mostRight = cur.left;
 9             if (mostRight != null) {//如果有左子树,没有左子树则直接跳过
10                 while (mostRight.right != null && mostRight != cur) {//找到左子树的最右节点
11                     mostRight = mostRight.right;
12                 }
13                 if (mostRight.right == null) {//对应情况2-(1)
14                     mostRight.right = cur;
15                     cur = cur.left;
16                     continue;//对应情况的所有操作已经结束,直接进行下一次循环
17                 } else {//对应情况2-(2)
18                     mostRight.right = null;
19                 }
20             }
21             //情况1和情况2-(2)都要执行该操作
22             cur = cur.right;
23         }
24     }

 

5.将Morris遍历转为前序/中序/后序遍历

1.先序遍历:
* 规则:如果这个节点只被遍历到1次,则再被遍历到时直接输出.如果被遍历到2次,则在第1次被遍历到时就输出‘

 

代码:

 1 public static void MorrisPre(Node root) {//先序遍历
 2         if (root == null) {
 3             return;
 4         }
 5         Node cur = root;
 6         Node mostRight = null;
 7         while (cur != null) {//cur为空时遍历才结束
 8             mostRight = cur.left;
 9             if (mostRight != null) {//如果有左子树,没有左子树则直接跳过
10                 while (mostRight.right != null && mostRight != cur) {//找到左子树的最右节点
11                     mostRight = mostRight.right;
12                 }
13                 if (mostRight.right == null) {//对应情况2-(1)
14                     System.out.print(cur.val + " ");//遍历两次的节点第一次被遍历到
15                     mostRight.right = cur;
16                     cur = cur.left;
17                     continue;//对应情况的所有操作已经结束,直接进行下一次循环
18                 } else {//对应情况2-(2)
19                     mostRight.right = null;
20                 }
21             } else {//对应只被遍历一次的节点,遍历到直接输出
22                 System.out.print(cur.val + " ");
23             }
24             //情况1和情况2-(2)都要执行该操作
25             cur = cur.right;
26         }
27     }

 

2.中序遍历:

规则:如果这个节点只被遍历到1次,则再被遍历到时直接输出.如果被遍历到2次,则在第2次被遍历到时输出

代码:

 1 public static void MorrisIn(Node root) {//中序遍历
 2         if (root == null) {
 3             return;
 4         }
 5         Node cur = root;
 6         Node mostRight = null;
 7         while (cur != null) {//cur为空时遍历才结束
 8             mostRight = cur.left;
 9             if (mostRight != null) {//如果有左子树,没有左子树则直接跳过
10                 while (mostRight.right != null && mostRight != cur) {//找到左子树的最右节点
11                     mostRight = mostRight.right;
12                 }
13                 if (mostRight.right == null) {//对应情况2-(1)
14                     mostRight.right = cur;
15                     cur = cur.left;
16                     continue;//对应情况的所有操作已经结束,直接进行下一次循环
17                 } else {//对应情况2-(2)
18                     mostRight.right = null;
19                 }
20             }
21             System.out.print(cur.val + " ");//包含了非叶节点第二次被遍历到和叶节点第一次被遍历到
22             //情况1和情况2-(2)都要执行该操作
23             cur = cur.right;
24         }
25     }

 

posted @ 2022-05-07 21:01  jue1e0  阅读(74)  评论(0)    收藏  举报