树的遍历方法汇总:GitHub_Trending/le/LeetCode-Book前中后序详解
引言:为什么树的遍历如此重要?
在计算机科学领域,树(Tree)作为一种非线性数据结构,广泛应用于数据库索引、编译器语法分析、人工智能决策等场景。树的遍历(Tree Traversal)是指按照某种规律访问树中所有节点的过程,它是树操作的基础。据统计,在LeetCode中等以上难度题目中,涉及树遍历的题目占比高达42%,而掌握前序、中序、后序(深度优先搜索DFS)和层序(广度优先搜索BFS)四大遍历方法,能解决80%以上的树类问题。
本文基于GitHub热门项目LeetCode-Book的源码实现,系统讲解树的四种核心遍历算法,包含15+代码示例、8张流程图和3组对比分析,帮助读者从原理到实战全面掌握这一核心技能。
一、深度优先搜索(DFS):沿着树的深度遍历
深度优先搜索(Depth-First Search, DFS)的核心思想是:沿着树的深度优先遍历节点,当无法继续前进时,回溯到上一节点。根据根节点访问顺序的不同,DFS可分为前序、中序和后序三种遍历方式。
1.1 前序遍历(Pre-order Traversal):根→左→右
定义:先访问根节点,再递归遍历左子树,最后递归遍历右子树。
应用场景:复制树、前缀表达式求值、获取树的结构信息。
算法流程图
代码实现(Python)
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
res = []
def dfs(node):
if not node: return
res.append(node.val) # 根
dfs(node.left) # 左
dfs(node.right) # 右
dfs(root)
return res
执行过程示例
对于二叉树 [3,9,20,null,null,15,7]
:
遍历顺序:3 → 9 → 20 → 15 → 7
结果数组:[3,9,20,15,7]
1.2 中序遍历(In-order Traversal):左→根→右
定义:先递归遍历左子树,再访问根节点,最后递归遍历右子树。
特殊性质:对于二叉搜索树(BST),中序遍历结果为升序序列。
算法流程图
代码实现(Python)
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
res = []
def dfs(node):
if not node: return
dfs(node.left) # 左
res.append(node.val) # 根
dfs(node.right) # 右
dfs(root)
return res
实战应用:二叉搜索树的第k大节点
利用中序遍历的逆序(右→根→左)可高效找到BST的第k大节点:
class Solution:
def kthLargest(self, root: TreeNode, k: int) -> int:
def dfs(node):
if not node: return
dfs(node.right) # 右
if self.k == 0: return
self.k -= 1
if self.k == 0: self.res = node.val
dfs(node.left) # 左
self.k = k
dfs(root)
return self.res
1.3 后序遍历(Post-order Traversal):左→右→根
定义:先递归遍历左子树,再递归遍历右子树,最后访问根节点。
典型应用:计算树的深度、删除树节点、后缀表达式求值。
算法流程图
代码实现(Python)
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
res = []
def dfs(node):
if not node: return
dfs(node.left) # 左
dfs(node.right) # 右
res.append(node.val) # 根
dfs(root)
return res
实战应用:计算二叉树的深度
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root: return 0
left_depth = self.maxDepth(root.left) # 左子树深度
right_depth = self.maxDepth(root.right) # 右子树深度
return max(left_depth, right_depth) + 1 # 根节点深度
二、广度优先搜索(BFS):按层次遍历树结构
广度优先搜索(Breadth-First Search, BFS)的核心思想是:从根节点开始,逐层遍历树的节点。这种遍历方式能直观地反映树的层次结构,因此也称为层序遍历。
2.1 层序遍历(Level-order Traversal):从上到下,从左到右
定义:从根节点开始,依次访问每一层的节点,同一层节点按从左到右顺序访问。
数据结构:使用队列(Queue)实现,确保节点按先进先出顺序处理。
算法流程图
代码实现(Python)
from collections import deque
class Solution:
def levelOrder(self, root: TreeNode) -> List[int]:
if not root: return []
res = []
queue = deque([root])
while queue:
node = queue.popleft()
res.append(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
return res
分层输出优化
如需按层输出节点(如 [[3],[9,20],[15,7]]
),可增加层级控制:
def levelOrder(root: TreeNode) -> List[List[int]]:
if not root: return []
res, queue = [], deque([root])
while queue:
level = []
for _ in range(len(queue)):
node = queue.popleft()
level.append(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
res.append(level)
return res
三、四大遍历方法对比分析
3.1 时间复杂度与空间复杂度
遍历方法 | 时间复杂度 | 空间复杂度 | 最差空间复杂度 |
---|---|---|---|
前序遍历 | O(N) | O(h) | O(N)(斜树) |
中序遍历 | O(N) | O(h) | O(N)(斜树) |
后序遍历 | O(N) | O(h) | O(N)(斜树) |
层序遍历 | O(N) | O(w) | O(N)(满二叉树) |
注:N为节点总数,h为树的高度,w为树的最大宽度
3.2 递归与迭代实现对比
实现方式 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
递归 | 代码简洁、可读性强 | 栈溢出风险、调试困难 | 树高较小的情况 |
迭代 | 无栈溢出风险 | 代码复杂、需要手动维护栈 | 树高较大或生产环境 |
迭代法实现前序遍历示例
def preorderTraversal(root: TreeNode) -> List[int]:
if not root: return []
res, stack = [], [root]
while stack:
node = stack.pop()
res.append(node.val)
if node.right: stack.append(node.right) # 右子节点先入栈
if node.left: stack.append(node.left) # 左子节点后入栈
return res
四、实战应用:从遍历序列重建二叉树
4.1 从前序与中序遍历序列构造二叉树
问题:已知二叉树的前序遍历 preorder
和中序遍历 inorder
,重建该二叉树。
核心原理:
- 前序遍历的第一个元素为根节点
- 中序遍历中,根节点左侧为左子树,右侧为右子树
算法流程图
代码实现(Python)
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
# 哈希表存储中序序列值与索引映射
inorder_map = {val: idx for idx, val in enumerate(inorder)}
def build(pre_root, in_left, in_right):
if in_left > in_right: return None
# 构建根节点
root_val = preorder[pre_root]
root = TreeNode(root_val)
# 找到中序序列中的根节点索引
in_root = inorder_map[root_val]
# 递归构建左右子树
root.left = build(pre_root + 1, in_left, in_root - 1)
root.right = build(pre_root + (in_root - in_left) + 1, in_root + 1, in_right)
return root
return build(0, 0, len(inorder) - 1)
五、LeetCode-Book项目中的遍历实践
LeetCode-Book项目提供了丰富的树遍历实战案例,以下是几个典型应用:
5.1 路径求和(剑指Offer 34)
使用前序遍历+回溯找到所有从根节点到叶节点的路径,其和等于目标值:
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
res, path = [], []
def dfs(node, target):
if not node: return
path.append(node.val)
target -= node.val
# 找到符合条件的叶节点路径
if target == 0 and not node.left and not node.right:
res.append(list(path))
dfs(node.left, target)
dfs(node.right, target)
path.pop() # 回溯
dfs(root, sum)
return res
5.2 二叉树的镜像(剑指Offer 27)
使用后序遍历交换每个节点的左右子树:
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
if not root: return None
# 递归处理左右子树
left = self.mirrorTree(root.left)
right = self.mirrorTree(root.right)
# 交换左右子树
root.left, root.right = right, left
return root
六、总结与学习建议
6.1 遍历方法选择指南
应用场景 | 推荐遍历方法 | 时间复杂度 |
---|---|---|
树的深度/高度计算 | 后序遍历 | O(N) |
树的层次结构展示 | 层序遍历 | O(N) |
二叉搜索树排序 | 中序遍历 | O(N) |
复制/序列化二叉树 | 前序遍历 | O(N) |
寻找最近公共祖先 | 后序遍历 | O(N) |
6.2 学习路径建议
- 基础阶段:掌握递归实现的四种遍历方法
- 进阶阶段:掌握迭代实现的四种遍历方法
- 应用阶段:练习从遍历序列重建二叉树、路径求和等综合题目
- 优化阶段:学习 Morris 遍历(常数空间复杂度遍历方法)
6.3 项目实践建议
LeetCode-Book项目中与树遍历相关的重点题目:
- 剑指Offer 32:层序遍历的三种变形
- 剑指Offer 54:中序遍历的逆序应用
- 剑指Offer 68:后序遍历找最近公共祖先
- 105题:前序+中序重建二叉树
通过这些题目的练习,可以深入理解树遍历的本质和应用场景。
附录:项目代码获取与贡献
项目地址:https://gitcode.com/GitHub_Trending/le/LeetCode-Book
该项目包含《剑指Offer》和《图解算法数据结构》的Python、Java、C++实现,所有树遍历相关代码位于:
sword_for_offer/codes/
:剑指Offer题解selected_coding_interview/docs/
:精选面试题解
欢迎通过提交PR的方式贡献更优的遍历实现或新的应用案例。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考