二叉树遍历终极指南:从入门到精通的前中后序+层序全解析
二叉树遍历是算法面试中的高频考点,掌握不同遍历方式的实现原理和应用场景,能显著提升解题效率。本文将系统讲解前序、中序、后序三种深度优先遍历(DFS)和层序遍历(BFS)的实现方法,结合GitHub_Trending/le/LeetCode-Book中的经典例题,帮助读者快速掌握树结构的核心操作。
树遍历基础概念
二叉树(Binary Tree)是每个节点最多拥有两个子节点的树结构,遍历(Traversal)则是按某种规则访问树中所有节点的过程。根据访问顺序的不同,可分为深度优先和广度优先两大类:
- 深度优先遍历(DFS):沿着树的深度优先访问节点,包括前序(根-左-右)、中序(左-根-右)、后序(左-右-根)三种方式
- 广度优先遍历(BFS):按层次顺序访问节点,又称层次遍历
遍历顺序可视化
以下是三种DFS遍历顺序的示意图(以[剑指 Offer 32 - I. 从上到下打印二叉树](https://link.gitcode.com/i/37c06361df6c0b4488a3abf7fd1a085a/blob/c12faa39f70b5ddbcd2830db88ac74fea599442b/sword_for_offer/docs/剑指 Offer 32 - I. 从上到下打印二叉树.md?utm_source=gitcode_repo_files)中的示例树为例):
- 前序遍历:A → B → D → E → C → F → G
- 中序遍历:D → B → E → A → F → C → G
- 后序遍历:D → E → B → F → G → C → A
- 层序遍历:A → B → C → D → E → F → G
深度优先遍历(DFS)实现
1. 前序遍历(Pre-order)
前序遍历的访问顺序为:根节点 → 左子树 → 右子树,是最直观的遍历方式。
递归实现
递归实现逻辑清晰,直接按照定义编写:
# [sword_for_offer/codes/python/sfo_27_mirror_of_a_binary_tree_s2.py]
def preorder_traversal(root):
result = []
def dfs(node):
if not node:
return
result.append(node.val) # 访问根节点
dfs(node.left) # 递归左子树
dfs(node.right) # 递归右子树
dfs(root)
return result
迭代实现
使用栈(Stack)模拟递归过程,需要注意右子节点先入栈:
def preorder_traversal(root):
if not root:
return []
result = []
stack = [root]
while stack:
node = stack.pop()
result.append(node.val) # 访问根节点
if node.right: # 右子节点先入栈
stack.append(node.right)
if node.left: # 左子节点后入栈
stack.append(node.left)
return result
2. 中序遍历(In-order)
中序遍历的访问顺序为:左子树 → 根节点 → 右子树,对二叉搜索树(BST)进行中序遍历可得到有序序列。
递归实现
def inorder_traversal(root):
result = []
def dfs(node):
if not node:
return
dfs(node.left) # 递归左子树
result.append(node.val) # 访问根节点
dfs(node.right) # 递归右子树
dfs(root)
return result
迭代实现
中序遍历的迭代实现相对复杂,需要先遍历至最左节点:
def inorder_traversal(root):
result = []
stack = []
current = root
while current or stack:
# 遍历至最左节点
while current:
stack.append(current)
current = current.left
# 访问节点
current = stack.pop()
result.append(current.val)
# 转向右子树
current = current.right
return result
3. 后序遍历(Post-order)
后序遍历的访问顺序为:左子树 → 右子树 → 根节点,常用于计算子树大小、删除节点等场景。
递归实现
def postorder_traversal(root):
result = []
def dfs(node):
if not node:
return
dfs(node.left) # 递归左子树
dfs(node.right) # 递归右子树
result.append(node.val) # 访问根节点
dfs(root)
return result
迭代实现(双栈法)
使用两个栈实现后序遍历,第一个栈用于遍历节点,第二个栈用于存储结果:
def postorder_traversal(root):
if not root:
return []
result = []
stack1 = [root]
stack2 = []
while stack1:
node = stack1.pop()
stack2.append(node.val)
if node.left:
stack1.append(node.left)
if node.right:
stack1.append(node.right)
# 反转结果得到后序遍历
return stack2[::-1]
广度优先遍历(BFS)实现
层序遍历按层次顺序访问节点,实现方式通常为队列(Queue):
基础层序遍历
# [sword_for_offer/docs/剑指 Offer 32 - I. 从上到下打印二叉树.md]
def level_order(root):
if not root:
return []
result = []
queue = [root]
while queue:
node = queue.pop(0)
result.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
分层层序遍历
如需将每层节点分开存储,可记录每层节点数量:
# [sword_for_offer/docs/剑指 Offer 32 - II. 从上到下打印二叉树 II.md]
def level_order(root):
if not root:
return []
result = []
queue = [root]
while queue:
level_size = len(queue)
current_level = []
for _ in range(level_size):
node = queue.pop(0)
current_level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(current_level)
return result
之字形层序遍历
实现锯齿形层序遍历,需要根据层数决定节点添加方向:
# [sword_for_offer/docs/剑指 Offer 32 - III. 从上到下打印二叉树 III.md]
def level_order(root):
if not root:
return []
result = []
queue = [root]
is_even_level = False
while queue:
level_size = len(queue)
current_level = []
for _ in range(level_size):
node = queue.pop(0)
current_level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
# 偶数层反转
if is_even_level:
current_level = current_level[::-1]
result.append(current_level)
is_even_level = not is_even_level
return result
遍历算法应用场景
不同遍历方式适用于不同场景,以下是常见应用:
前序遍历
- 树的拷贝
- 前缀表达式求值
- [LCR 124. 推理二叉树](https://link.gitcode.com/i/37c06361df6c0b4488a3abf7fd1a085a/blob/c12faa39f70b5ddbcd2830db88ac74fea599442b/leetbook_ioa/docs/LCR 124. 推理二叉树.md?utm_source=gitcode_repo_files)(根据前序遍历重建二叉树)
中序遍历
- 二叉搜索树排序
- [剑指 Offer 54. 二叉搜索树的第 k 大节点](https://link.gitcode.com/i/37c06361df6c0b4488a3abf7fd1a085a/blob/c12faa39f70b5ddbcd2830db88ac74fea599442b/sword_for_offer/docs/剑指 Offer 54. 二叉搜索树的第 k 大节点.md?utm_source=gitcode_repo_files)
- 验证二叉搜索树
后序遍历
- 计算树的深度
- 删除树节点
- [剑指 Offer 55 - I. 二叉树的深度](https://link.gitcode.com/i/37c06361df6c0b4488a3abf7fd1a085a/blob/c12faa39f70b5ddbcd2830db88ac74fea599442b/sword_for_offer/docs/剑指 Offer 55 - I. 二叉树的深度.md?utm_source=gitcode_repo_files)
层序遍历
- 计算树的宽度
- 寻找二叉树最底层最左边的值
- [剑指 Offer 32 - III. 从上到下打印二叉树 III](https://link.gitcode.com/i/37c06361df6c0b4488a3abf7fd1a085a/blob/c12faa39f70b5ddbcd2830db88ac74fea599442b/sword_for_offer/docs/剑指 Offer 32 - III. 从上到下打印二叉树 III.md?utm_source=gitcode_repo_files)
遍历算法复杂度分析
| 遍历方式 | 时间复杂度 | 空间复杂度 | 实现方式 |
|---|---|---|---|
| 前序遍历 | O(N) | O(N) | 递归/迭代 |
| 中序遍历 | O(N) | O(N) | 递归/迭代 |
| 后序遍历 | O(N) | O(N) | 递归/迭代 |
| 层序遍历 | O(N) | O(N) | 队列 |
其中N为二叉树节点数量,空间复杂度主要取决于栈/队列的大小,最坏情况下(斜树)为O(N),平均情况下为O(logN)。
总结与进阶
掌握二叉树遍历是学习更复杂树结构(如红黑树、B+树)的基础,建议通过以下步骤巩固学习:
- 实现四种遍历的递归与迭代版本
- 完成剑指 Offer 32 系列层序遍历题目
- 尝试 Morris 遍历(常数空间复杂度遍历方法)
- 解决[selected_coding_interview/docs/102. 二叉树的层序遍历.md](https://link.gitcode.com/i/37c06361df6c0b4488a3abf7fd1a085a/blob/c12faa39f70b5ddbcd2830db88ac74fea599442b/selected_coding_interview/docs/102. 二叉树的层序遍历.md?utm_source=gitcode_repo_files)等进阶题目
更多二叉树相关题目和解题代码,请参考项目官方文档和[剑指 Offer 题目分类](https://link.gitcode.com/i/37c06361df6c0b4488a3abf7fd1a085a/blob/c12faa39f70b5ddbcd2830db88ac74fea599442b/sword_for_offer/剑指 Offer 题目分类.md?utm_source=gitcode_repo_files)。通过系统练习,相信你能在面试中轻松应对各类树遍历问题!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



