Morris算法
参考:https://www.cnblogs.com/blzm742624643/p/10021388.html
一、算法介绍
Morris算法充分利用了二叉树叶子结点下的空间,从而可以在时间复杂度为O(N),空间复杂度为O(1)的条件下,前中后序遍历二叉树(不是完全二叉树也可以使用)。
而常见的遍历二叉树的方法为递归和栈迭代,这两种方法的时间复杂度虽然也为O(N),但是空间复杂度需要O(N),因此Morris算法可以极大节省空间。
二、算法原理
首先来到当前结点记为cur。
1.如果cur无左孩子,cur向右移动。
2.如果cur有左孩子,那么找到cur左子树的最右的结点,记为mostRight。
2.1如果mostRight的right指针指向空,则让其指向cur,然后cur向左移动
2.2如果mostRight的right指针指向cur,让其指回空,然后cur向右移动。
三、算法实现
困难之处在于在遍历的子结点的时候如何重新返回其父结点?在Morris遍历算法中,通过修改叶子结点的左右空指针来指向其前驱或者后继结点来实现的。
1. 中序遍历
如果当前结点pNode的左孩子为空,那么输出该结点,并把该结点的右孩子作为当前结点;
如果当前结点pNode的左孩子非空,那么就找出该结点在中序遍历中的前驱结点pPre
当第一次访问该前驱结点pPre时,其右孩子必定为空,那么就将其右孩子设置为当前结点,以便根据这个指针返回到当前结点pNode中,并将当前结点pNode设置为其左孩子;
当该前驱结点pPre的右孩子为当前结点,那么就输出当前结点,并把前驱结点的右孩子设置为空(恢复树的结构),将当前结点更新为当前结点的右孩子
重复以上两步,直到当前结点为空。
var inOrder3= function (root) { if(root === null) return; let cur = root; let res = []; while(cur){ if(cur.left === null){ res.push(cur.val); cur = cur.right; }else{ let node = cur.left; while(node!==null && node.right !== null && node.right !== cur){ node=node.right; } if(node.right === null){ node.right = cur; cur = cur.left; }else{ node.right = null; res.push(cur.val); cur = cur.right; } } } return res; };
2.前序遍历
与中序遍历类似,区别仅仅是输出的顺序不同。
var preOrder3= function (root) { if(root == null) return; let cur = root; let res = []; while(cur){ if(cur.left === null){ res.push(cur.val); cur = cur.right; }else{ let node = cur.left; while(node!==null && node.right !== null && node.right !== cur){ node=node.right; } if(node.right === null){ res.push(cur.val); node.right = cur; cur = cur.left; }else{ node.right = null; cur = cur.right; } } } return res; };
3.后序遍历
var postOrder3 = function (root) { if (root === null) return []; let cur = root; let res = []; var addPath=(node) =>{ let arr = []; while(node != null){ arr.push(node.val); node = node.right; } return arr.reverse(); } while (cur) { let node = cur.left; if (node !== null) { while (node !== null && node.right !== null && node.right !== cur) { node = node.right; } if (node.right === null) { node.right = cur; cur = cur.left; continue; } else { node.right = null; res.push(...addPath(cur.left)); } } cur = cur.right; } res.push(...addPath(root)); return res; };