后序遍历是一种访问顺序规则,而非递归算法是实现这种顺序的一种方式。它们的区别可以从两个层面理解:
✅ 1. 定义 vs 实现
项目 | 后序遍历 | 非递归算法 |
---|---|---|
本质 | 一种访问顺序(左 → 右 → 根) | 一种实现方式(用栈代替递归) |
是否具体算法 | 否,是规则 | 是,是代码实现 |
是否唯一实现方式 | 否,可用递归或非递归 | 否,也可用递归 |
✅ 2. 递归 vs 非递归:实现方式对比
对比维度 | 递归实现 | 非递归实现 |
---|---|---|
代码结构 | 简洁,利用函数调用栈 | 复杂,需手动维护栈 |
空间复杂度 | 依赖系统调用栈,最坏 O(n) | 手动栈,最坏 O(n) |
可读性 | 高 | 低 |
适用语言 | 所有支持递归的语言 | 所有语言(尤其适合不支持递归或栈深度受限的环境) |
调试难度 | 递归栈深时难调试 | 手动栈逻辑复杂,易出错 |
✅ 举个例子
假设有一棵二叉树:
A
/ \
B C
/ \
D E
- 后序遍历顺序:D → E → B → C → A
- 这个顺序可以用递归实现(简洁),也可以用非递归栈实现(更底层)
✅ 总结一句话
“后序遍历”是规则,“非递归算法”是用栈实现这个规则的一种方式。
二叉树的后序遍历是一种重要的树遍历方式,其访问顺序是:先遍历左子树,再遍历右子树,最后访问根节点。
以下是实现二叉树后序遍历的 Python 代码,包含了递归和迭代两种常见方法:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
# 递归实现后序遍历
def postorderTraversalRecursive(self, root: TreeNode) -> list[int]:
result = []
def helper(node):
if not node:
return
# 先遍历左子树
helper(node.left)
# 再遍历右子树
helper(node.right)
# 最后访问根节点
result.append(node.val)
helper(root)
return result
# 迭代实现后序遍历
def postorderTraversalIterative(self, root: TreeNode) -> list[int]:
if not root:
return []
result = []
stack = []
prev = None
while root or stack:
# 遍历到最左子节点
while root:
stack.append(root)
root = root.left
# 取出栈顶节点
root = stack.pop()
# 如果右子树为空或已访问过,则访问当前节点
if not root.right or root.right == prev:
result.append(root.val)
prev = root
root = None
else:
# 否则将当前节点重新入栈,处理右子树
stack.append(root)
root = root.right
return result
# 示例用法
if __name__ == "__main__":
# 构建一个示例二叉树
# 1
# \
# 2
# /
# 3
root = TreeNode(1)
root.right = TreeNode(2)
root.right.left = TreeNode(3)
solution = Solution()
print("递归后序遍历结果:", solution.postorderTraversalRecursive(root)) # 输出: [3, 2, 1]
print("迭代后序遍历结果:", solution.postorderTraversalIterative(root)) # 输出: [3, 2, 1]
代码解析:
-
首先定义了
TreeNode
类来表示二叉树的节点,每个节点包含值、左子节点和右子节点。 -
递归实现:
- 使用辅助函数
helper
进行递归 - 递归遍历左子树,再递归遍历右子树,最后将当前节点的值加入结果列表
- 递归方法简洁直观,符合后序遍历的定义
- 使用辅助函数
-
迭代实现:
- 使用栈来模拟递归过程
- 先遍历到最左子节点,然后处理节点
- 通过
prev
指针记录上一个访问的节点,用于判断右子树是否已访问 - 当右子树为空或已访问时,才访问当前节点
两种方法都能得到相同的遍历结果,对于示例中的二叉树,后序遍历结果为[3, 2, 1]
。递归方法代码简洁但可能受到递归深度限制,迭代方法则避免了这个问题。
二叉树的后序遍历
后序遍历(Postorder Traversal)是指按照以下顺序访问二叉树的节点:
- 首先遍历左子树;
- 然后遍历右子树;
- 最后访问根节点。
后序遍历的递归算法:
void PostOrder(BiTree T) {
if (T != NULL) {
PostOrder(T->lchild); // 遍历左子树
PostOrder(T->rchild); // 遍历右子树
printf("%c", T->data); // 访问根节点
}
}
后序遍历的非递归算法(使用栈):
void PostOrder(BiTree T) {
SqStack S;
BiTNode *p = T;
BiTNode *r = NULL; // 标记最近访问的节点
InitStack(S);
while (p != NULL || !StackEmpty(S)) {
if (p != NULL) { // 走到最左边
Push(S, p);
p = p->lchild;
} else {
GetTop(S, p); // 读栈顶节点
if (p->rchild != NULL && p->rchild != r) {
p = p->rchild; // 转向右子树
Push(S, p);
p = p->lchild;
} else {
Pop(S, p); // 弹出并访问节点
printf("%c", p->data);
r = p; // 记录最近访问的节点
p = NULL;
}
}
}
}