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 }