内容:
1、什么是morris遍历
2、morris遍历规则与过程
3、先序及中序
4、后序
5、morris遍历时间复杂度分析
1、什么是morris遍历
关于二叉树先序、中序、后序遍历的递归和非递归版本,在这里有详细代码:https://www.cnblogs.com/wyb666/p/10176980.html
明显这6种遍历算法的时间复杂度都需要 O(H) (H 为树高)的额外空间复杂度
另外因为二叉树遍历过程中只能向下查找孩子节点而无法回溯父结点,因此这些算法借助栈来保存要回溯的父节点
并且栈要保证至少能容纳下 H 个元素(比如遍历到叶子结点时回溯父节点,要保证其所有父节点在栈中)
而morris遍历则能做到时间复杂度仍为 O(N) 的情况下额外空间复杂度只需 O(1) 。
2、morris遍历规则与过程
首先在介绍morris遍历之前,我们先把先序、中序、后序定义的规则抛之脑后,
比如先序遍历在拿到一棵树之后先 遍历头结点然后是左子树后是右子树,并且在遍历过程中对于子树的遍历仍是这样。
在忘掉这些遍历规则之后,我们来看一下morris遍历定义的标准:
(1)定义一个遍历指针 cur ,该指针首先指向头结点
(2)判断 cur 的左子树是否存在
如果 cur 的左孩子为空,说明 cur 的左子树不存在,那么 cur右移(cur=cur.right)
如果 cur 的左孩子为cur,说明 cur 的左子树存在,找出该左子树上最右节点记为 mostRight
如果mostRight 的右孩子为空,那就让其指向 cur ( mostRight.right=cur ),并左移 cur ( cur=cur.left )
如果mostRight 的右孩子不为空,那么让 cur 右移( cur=cur.right ),并将 mostRight 的右孩子置空
(3)经过步骤2之后,如果 cur 不为空,那么继续对 cur 进行步骤2,否则遍历结束
下图所示举例演示morris遍历的整个过程:
代码:
1 public static void morrisProcess(Node head){ 2 // morris遍历的过程 3 if(head == null){ 4 return; 5 } 6 Node cur = head; 7 Node mostRight = null; 8 while(cur!=null){ 9 mostRight = cur.left; 10 if(mostRight != null){ 11 while(mostRight.right!= null && mostRight.right!=cur){ 12 mostRight = mostRight.right; 13 } 14 if(mostRight.right==null){ 15 mostRight.right = cur; 16 cur = cur.left; 17 continue; 18 } else{ 19 mostRight.right = null; 20 } 21 } 22 cur = cur.right; 23 } 24 }
3、先序及中序
4、后序
5、morris遍历时间复杂度分析