后序遍历:递归+非递归实现
后序遍历:递归+非递归实现
基本概念
后序遍历(Postorder Traversal) 是二叉树深度优先遍历(DFS)的一种。其访问顺序为:左子树 → 右子树 → 根结点。
- 后序遍历常用于需要先处理子结点再处理父结点的场景(如删除树、计算表达式树的值)。
- 递归实现简单,非递归实现相对复杂,需要借助双栈或标记法来记录结点是否已访问过右子树。
算法步骤
- 递归版:
- 若当前结点为空,直接返回。
- 递归遍历左子树。
- 递归遍历右子树。
- 访问当前结点(如记录值)。
- 非递归版(双栈法):
- 利用两个栈
s1和s2。 - 将根结点压入
s1。 - 循环弹出
s1栈顶结点,将其压入s2,然后将其左孩子和右孩子依次压入s1(先左后右,则弹出时顺序不影响)。 - 最终
s2的出栈顺序即为后序遍历顺序(根在最后)。
- 利用两个栈
- 非递归版(单栈+标记法):
- 使用一个栈,每个元素为
(node, visited),visited表示右子树是否已处理。 - 初始压入
(root, False)。 - 循环处理:
- 弹出栈顶。
- 若结点为空则跳过。
- 若
visited为True,则访问该结点。 - 否则,重新压入
(node, True),然后先压右孩子(node.right, False),再压左孩子(node.left, False)(确保左右子树先被处理)。
- 使用一个栈,每个元素为
内部实现
1 | from typing import List, Optional |
复杂度分析
| 版本 | 时间复杂度 | 空间复杂度 | 说明 |
|---|---|---|---|
| 递归 | O(n) | O(h) | h 为树高,最坏 O(n)(斜树),平均 O(log n) |
| 双栈法 | O(n) | O(n) | 两个栈共存储 O(n) 结点 |
| 单栈标记法 | O(n) | O(h) | 最坏 O(n)(斜树),平均 O(log n) |
- 时间复杂度:每个结点访问一次,O(n)。
- 空间复杂度:递归和单栈标记法依赖栈深度;双栈法需要额外的输出栈,空间 O(n)。
应用场景
- 删除树:必须先删除子结点再删除父结点,后序遍历天然支持。
- 表达式树求值(后缀表达式):后序遍历可直接计算表达式的值(左右子树值计算完后,再根据根运算符计算)。
- 目录树大小统计:先计算子目录大小,再累加到父目录。
- 计算树的高度:后序遍历可以获取左右子树的高度,然后取最大值加一。
- 判断平衡二叉树:后序遍历同时返回高度和是否平衡。
- 真实系统:
- 文件系统删除(
rm -rf递归删除目录时,先删子文件再删目录)。 - 依赖解析(如构建工具中的依赖图,先处理依赖再处理当前节点)。
- 内存垃圾回收中的引用计数(对象不再被引用时,先释放成员,再释放自身)。
- 文件系统删除(
相关链接
- 145.二叉树的后序遍历
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!





