二叉树非递归三种遍历的统一模板

今天在LeetCode刷题的时候,遇到一个二叉树非递归后序遍历的题目。
评论区发现一位大神给的前中后序都通用的非递归模板,着实受益匪浅,因此记录一下。

原文参见:https://leetcode-cn.com/problems/binary-tree-postorder-traversal/solution/mo-fang-di-gui-zhi-bian-yi-xing-by-sonp/
用C++写的,这里我改成了Python。

二叉树结点的定义如下:
from typing import List


# Definition for a binary tree node.

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
后序遍历的模板代码

首先应该说清楚的是:除了前序遍历外,对结点的首次访问和对结点的处理并不是同时发生的,后两者对结点的处理发生在第二次访问时——例如中序遍历,每个结点首次访问到之后,还会去访问它的左子树,直至左子树全部访问完毕再次回到这个结点,才是对当前结点的访问/处理。
因此有必要标识清楚当前是对结点的第几次访问 ——
以上就是下面的代码中结点压入栈的时候要额外让None进栈的原因,遇到None则对其下一个结点进行处理 。

(吐槽一下,Python代码注释的字体好丑……)

class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        res = []  # 储存遍历结果
        stack = []  # 模拟栈
        if root:
            stack.append(root)  # 根结点进栈保证循环正常进行,同时可以处理空树while stack:
​            t = stack.pop()  # 每一步拿出一个点if t:
                # 模拟递归的压栈顺序
​                stack.append(t)  # 顺着访问,因此逆着压栈,后序遍历是左右根,就先进根
​                stack.append(None)  # None用来表示下个结点从栈里面弹出来已经是第二次访问了if t.right:
​                    stack.append(t.right)  # 保证非空再进右if t.left:
​                    stack.append(t.left)  # 保证非空再进左else:  # 在第二次访问的时候,弹栈,对弹出的元素进行处理
​                res.append(stack.pop().val)  # 此处可以写对当前结点进行任何处理的代码

        # 对于前序遍历,只要把根左右的遍历顺序逆向——右左根,把对应的代码顺序调整一下即可
        # 中序遍历也是如此——右根左
        # 最后提一句,因为前序遍历首次访问和对节点的处理是同时发生的,因此代码可以简化return res
完整非递归后序遍历代码

下面贴一个可以直接运行的代码,方便理清思路和调试。

from typing import List


# Definition for a binary tree node.
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        res = []
        stack = []
        if root:
            stack.append(root)

        while stack:
            t = stack.pop()
            if t:
                stack.append(t)  # 1
                stack.append(None)  # 1
                if t.right:  # 2
                    stack.append(t.right)
                if t.left:  # 3
                    stack.append(t.left)
                # 对于前序遍历和中序遍历,调整# 1的顺序即可
                # 把#1 放在#2与#3之间就是中序遍历
                # 把#1 放在#3之后就是前序遍历
            else:
                res.append(stack.pop().val)

        return res


if __name__ == '__main__':
    # 构造下面的一棵二叉树
    #           1
    #         /   \
    #        2     3
    #         \
    #          4
    r = TreeNode(1)
    r.left = TreeNode(2)
    r.right = TreeNode(3)
    r.left.right = TreeNode(4)

    # 后序遍历
    solution = Solution()
    post_order = solution.postorderTraversal(r)
    print(post_order)
对应的前序遍历与中序遍历

前序遍历只要将后序遍历中“根右左”的顺序调整为对应的“右左根”即可:

# 前序遍历中 if t: 内的代码调整为如下格式即可。
    if t.right:
        stack.append(t.right)
    if t.left:
        stack.append(t.left)
    stack.append(t)
    stack.append(None)

中序遍历大家可以自己试试~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值