Morris算法先序、中序遍历二叉树

常见的二叉树遍历算法有递归非递归形式,但实际内部都是要通过栈来进行存储,而Morris算法只需要O(1)的空间复杂度,通过调整叶子节点的指针即可完成二叉树的遍历。
Morris算法先序、中序遍历二叉树
如上图所示,4 5 6都是叶子节点,他们的left,right都指向None,我们可以将right指针利用起来,将叶子节点的right 指针指向下一个待访问的节点,这样我们就不需要用栈,就可以挨个遍历二叉树的所有节点。
Morris算法的要点如下:

  • 每个非叶子节点被访问两次(除了第二条中的情况),第一次访问时为了找到该节点的左子树的最右节点并将该节点的right指针指向当前节点。第二次是通过上个节点的right指针过来的。
    以先序遍历为例比如上图中的节点2,第一次访问是通过1left指针到达的,第二次访问时通过4的right指针到达的
  • (先序和中序遍历中)当节点的左子树为None时立即访问该节点
  • 每条边访问了两次,用时间换空间
  • 第二次访问节点的时候,再次找到左子树的最右节点,此时该节点right指针被指向了当前节点,我们要将他复原

先序遍历

class Solution:
    def preorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        res = []
        pNode = root
        while(pNode):
            if pNode.left == None:
            #左子树为空的时候直接访问,并将指针移动到右子树的根节点
                res.append(pNode.val)
                pNode = pNode.right
            else:
            #因为左子树不为空,所以我们能找到左子树的最右节点
                tmp = pNode.left
                while(tmp.right and tmp.right != pNode):
                    tmp = tmp.right
                if tmp.right == None:
                #注意这里当tmp.right ==None时才访问,因为先序遍历中,这是第一次访问根节点,等第二次访问的时候左子树已经访问完了
                    res.append(pNode.val)
                    tmp.right =pNode
                    pNode = pNode.left
                else:
                # tmp.right ==pNode,表示这是第二次访问根节点了,进行还原操作
                    tmp.right = None
                    pNode = pNode.right
        return res

中序遍历

与先序遍历只有一点点不同,第二次访问到节点的时候才读取它的值。

class Solution:
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        res = []
        pNode = root
        while(pNode):
            if pNode.left == None:
                res.append(pNode.val)
                pNode = pNode.right
            else:
                tmp = pNode.left
                while(tmp.right and tmp.right!=pNode):
                    tmp = tmp.right
                if tmp.right == None:
                    tmp.right = pNode
                    pNode = pNode.left
                else:
                    res.append(pNode.val)
                    tmp.right =None
                    pNode = pNode.right
        return res