题目
给定一棵二叉树的头节点head,完成二叉树的先序、中序、后序遍历。如果二叉树的节点为N,则要求时间复杂度为O(N),额外空间复杂度为O(1)。
Morris遍历的的介绍
Morris遍历的二叉树遍历算法的超强进阶算法,该算法可以将非递归遍历中的空间复杂度降为O(1)。从而能够实现时间复杂度为O(N),空间复杂度为O(1)的精妙算法。普通的递归于非递归的解法,其中都使用了栈的结构,递归方法使用了函数栈,非递归的方法则是自己手动维护了一个栈。两者的额外空间都与树的高度相关,空间复杂度为O(h),h为二叉树的高度。
普通的递归与非递归的解法,都使用了栈,在处理完二叉树的某个节点之后可以回到上层去。
Morris遍历的实质
避免使用栈结构,让下层到上层存在指针,具体的是通过让底层节点指向null的空闲指针指回上层的某个节点,从而完成下层到上层的移动。
空闲指针
某些孩子不存在右孩子节点,那么这个节点的right指针就指向null,我们称之为空闲状态。Morris遍历正是利用了这些空闲指针。
Morris遍历的实现原则
假设当前节点为 cur,初始时cur就是整棵树的头节点,根据以下的标准让cur进行移动
-
如果cur为空的情况下,则过程停止,否则继续下面的过程。
-
如果cur无左孩子。则cur向右移动(cur = cur.right)
-
如果cur存在左孩子,找到cur左子树最右节点,记为mostright
-
如果mostright的右指针指向空,让其指向cur,cur向左移动(cur = cur.left)
如果mostright的右指针指向cur,让其指向空,cur向右移动(cur = cur.right)
假设一棵二叉树如图所示,使用该二叉树进行遍历。
-
初始时,cur来到节点4,此时cur存在左子树,故按原则,找到左子树的最右节点(即节点3),发现节点3的右指针指向空,故让其指向cur。如下图所示,cur左移来到节点2。
-
cur来到2时,存在左子树,找到左子树的最右节点(即节点1),发现节点1的左指针是指向空,那么让其指向cur,如下图所示,cu r来到节点1。
-
cu r来到节点1时,cur此时不存在左子树,根据标准令cur向右指针方向移动,所以回到了节点2
-
cur来到节点2,cur此时存在左子树,找到cur左子树的最右节点,即节点1,发现节点1是指向cur的,根据标准将其指向null树被调整为如下图所示的的样子,根据标准cur向右指针的方向移动,所以cur来到了节点3。
-
cur来到了节点3,cur此时不存在左子树,,根据标准令cur 向右指针方向移动,所以cu r来到了4。
-
cur节点来到4,此时cur存在左子树,找到cur左子树的最右节点,即节点3,发现节点3的指针是指向cur的,那么让其指向null,根据标准cur向右移动来到节点6,最后结果如下图。
-
cur来到节点6,cur此时存在左子树,找到左子树的最右节点,即节点5,发现节点5的右指针是指向空的,那么让其指向cur,根据标准,cur向左移动来到了节点5。
-
cur来到节点5,cur不存在左子树,根据标准令cur向右指针移动,故cur移动到了6.
-
cur来到节点6,cur存在右左子树,找cur的左子树的最右节点,即节点5,发现节点5的右指针指向cur,那么让其指向空,然后根据标准向右移动到节点7.
-
cur来到节点7,此时cur不存在左子树,根据标准向右移动,curl来到null的位置。
-
cur为空,过程停止。
-
以上的所有步骤都是按照我们之前的标准进行移动的,cur依次到达的节点为:4,2,1,2,3,4,6,5,6,7。这个序叫做Morris序。
代码
public static class Node{
public int value