二叉树的遍历

相信只要了解过二叉树,都知道二叉树的3种遍历方式:前序遍历、中序遍历、后序遍历。
甚至不夸张的说,其递归的遍历方法闭着眼睛也能写出来。所以本篇意不在记录其递归的写法,而是探寻其迭代的方法。

0、定义二叉树

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

1. 前序遍历

想要理解或者实现前序遍历方法,我们可以从其递归方法入手,了解其实现过程。

class Solution:
    def preorderTraversal(self, root: TreeNode):
        res = []
        
        def dfs(root):
            nonlocal res
            if not root:
                return 
            res.append(root.val)
            dfs(root.left)
            dfs(root.right)
        
        dfs(root)
        return res

将其递归的过程展开,就如同其下的方式:访问当前节点,进入左子节点,然后访问当前节点的左子节点……,遇到null则返回,然后访问节点的右子节点,由于节点不能反向找到其父节点,我们需要保存其右子节点。同时,我们需要从最近的右子节点开始访问,也即利用栈来代替递归算法中的调用栈。

dfs(root)
    print(root.val)
    dfs(root.left)
        print(root.left.val)
        dfs(root.left)
            null return
        dfs(root.right)
            print(root.right.val)
            dfs(root.left)
            ...

下面是其迭代方法的实现

class Solution:
    def preorderTraversal(self, root):
        res = []
        stack = []
        
        while stack or root:
            while root:
                res.append(root.val)
                stack.append(root.right)
                root = root.left
            root = stack.pop()
        
        return res

2. 中序遍历

中序遍历的递归调用过程如下,深入左子节点,当其为空则返回,访问节点,然后进入其右子节点。重复该过程。

dfs(root)
    dfs(root.left)
        dfs(root.left)
            null return
        print(root.val)
        dfs(root.right)
            dfs(root.left)
                dfs(root.left)
                ...

可以看到,我们需要先将左子节点保存,待其为空后,当问节点,进入右子树,继续……

class Solution:
    def inorderTraversal(self, root: TreeNode):
        res = []
        stack = []
        while stack or root:
            while root:
                stack.append(root)
                root = root.left
            root = stack.pop()
            res.append(root.val)
            root = root.right
        return res

3. 后序遍历

后序遍历可以看着是前序遍历的镜像,所以可以套用前序遍历的方法,但是需要将最后结果进行反转。

class Solution:
    def postorderTraversal(self, root):
        res = []
        stack = []
        
        while stack or root:
            while root:
                res.append(root.val)
                stack.append(root.left)
                root = root.right
            root = stack.pop()
        
        return res[::-1]

4. 颜色标记法

这个方法是leetcode解题中,针对前中后序遍历均适用,而且容易理解。
以后序遍历为例,其代码如下。需要注意的是,因为栈的后进先出结构,所以我们的入栈顺序为相反方向。
同理,如果是前序遍历,则入栈顺序为:右、左、中;
中序遍历的入栈顺序为:右、中、左。

class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        res = []
        white, gray = 1, 0
        stack = [(white, root)]
        while stack:
            color, node = stack.pop()
            if not node:
                continue
            if color == white:
                stack.append((gray, node))
                stack.append((white, node.right))
                stack.append((white, node.left))
            else:
                res.append(node.val)
        return res

5. leetcode

94. 二叉树的中序遍历

145. 二叉树的后序遍历

6. 参考

1、https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/yan-se-biao-ji-fa-yi-chong-tong-yong-qie-jian-ming/
2、https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/die-dai-fa-by-jason-2/

你可能感兴趣的:(二叉树的遍历)