帕先生之二叉树非递归遍历上篇

37 阅读3分钟

上期讲到二叉树的递归遍历, 那么本期来讲一下非递归遍历, 也就是迭代版本的代码怎么写

1、 前序遍历

中左右

binarytree.png

来模拟递归的过程, 特点是先进后出

入栈的元素首先放入栈底, 然后每次从栈顶弹出, 这也就是为什么先进后出

遇到root, 把10入栈

image.png

然后处理根节点, 弹出10, 同时push到 Res里

image.png

然后把左右孩子入栈, 这里为5和20, 注意因为最后是中左右的顺序, 而且栈是先进后出, 所以这里是先要把右孩子入栈, 再把左孩子入栈, 这样才能先弹出左孩子, 再弹出右孩子

image.png

弹出5, 同时把5 加入到Res里

image.png

然后继续处理 5 的左右孩子, 因为是中左右, 要先处理完左子树, 才能处理右子树, 所以此时是处理 5 的左右孩子, 为 4 和 6 ,即先把右孩子 6 入栈, 再把左孩子 4 入栈, 这样弹出的时候才能先弹出左孩子, 再弹出右孩子

image.png

弹出 4 , 把 4 加入到Res里

image.png

此时 4 已经是叶子节点了, 即没有左右孩子, 所以继续弹出 6 , 同时 把 6 加入到 Res

image.png

6 也是 叶子节点, 没有左右孩子, 则继续弹出 20 , 把 20 加入到 Res 里

image.png

然后把 20 的左右孩子入栈, 按照先进后出的原则, 先入右孩子, 再入左孩子

image.png

然后 弹出 2, 把 2 加入到 Res里

image.png

2 是叶子节点, 没有左右孩子, 继续弹出, 把 8 加入到 Res里

image.png

至此, 整个二叉树遍历完毕, 输出 10, 5, 4, 6, 20, 2, 8

代码实现

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if not root: return []
        stack, res = [], []
        stack.append(root)  # 首先把根节点加进来
        while stack:  # 只要栈不为空, 就一直执行
            temp = stack.pop()  # 入栈后, 我们要先弹出, 然后把val 加入到Res, 同时把左右孩子入栈
            res.append(temp.val)
            if temp.right:  #  因为栈是先进后出, 所以先加右孩子, 当然 先要判断右孩子是否存在
                stack.append(temp.right)
            if temp.left  # 再加 左孩子, 这样在下次pop的时候才能保证先弹出的是左孩子
                stack.append(temp.left)
        return res

2、 后序遍历

左右中

如果把左右中 颠倒一下 就是中右左, 然后把右左 换一下顺序呢 是不是就是中左右

看到中左右能想到什么, 不就是前序遍历吗?

那其实 现在我们只需要把上面代码改成中右左, 然后把结果 reverse一下, 就是我们的后序遍历

代码实现

先加入左孩子, 再加入右孩子, 弹出元素的时候就会先弹右孩子, 再弹出左孩子, 这样最后得到的结果就是中右左, 然后颠倒一下 左右中, 即是我们的后续遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if not root: return []
        stack, res = [root], []
        while stack:
            temp = stack.pop() 
            res.append(temp.val)
            if temp.left:  #  先加入左孩子
                stack.append(temp.left)
            if temp.right:  # 再加入右孩子
                stack.append(temp.right)
        return res[::-1]  // reverse一下

3、中序遍历

左中后

这个会比较特殊一点, 因为是先遍历左孩子, 然后处理根节点, 再遍历右孩子

前序和后序都是遍历根节点的同时 就处理了根节点, 而中序是要先遍历左孩子, 才能处理根节点.

下期会着重讲中序遍历(帕鲁先生累了, 呜呜呜)