树是计算机科学中最基础也最重要的数据结构之一,广泛应用于文件系统、数据库索引、游戏AI等领域。在处理树结构问题时,我们通常需要遍历整棵树来搜索特定节点或验证某些属性。根据遍历顺序和方向的不同,主要分为以下几种经典方法:
这几种方法各有特点,适用于不同场景。下面我将结合具体代码示例,详细解析每种方法的实现原理和适用场景。
颜色标记法本质上是DFS的一种变体,通过给节点赋予不同"颜色"来标记其访问状态。典型的三色标记法实现如下:
python复制WHITE = 0 # 未访问
GRAY = 1 # 访问中
BLACK = 2 # 已访问完成
def dfs(node):
if node.color == BLACK:
return
if node.color == GRAY:
raise Exception("检测到环")
node.color = GRAY
for child in node.children:
dfs(child)
node.color = BLACK
这种方法的优势在于:
颜色标记法特别适用于以下情况:
提示:在实现时,可以用整数代替颜色枚举,节省内存空间。对于大规模图,可以考虑使用位运算进一步优化。
BFS使用队列数据结构,保证节点按层级顺序被访问。以下是Python实现示例:
python复制from collections import deque
def bfs(root):
if not root:
return
queue = deque([root])
while queue:
level_size = len(queue)
for _ in range(level_size):
node = queue.popleft()
print(node.val) # 处理当前节点
for child in node.children:
if child:
queue.append(child)
BFS的一个关键特性是可以自然获取层级信息。我们常用两种方式处理层级:
对于某些特定问题,如二叉树右视图、最小深度等,BFS通常比DFS更高效。
自顶向下DFS是最直观的深度优先实现方式:
python复制def dfs(node, parent_val):
if not node:
return
# 处理当前节点(使用父节点信息)
node.val += parent_val
# 递归处理子节点
for child in node.children:
dfs(child, node.val)
这种方式的典型特点是:
常见应用包括:
自底向上DFS通常通过后序遍历实现:
python复制def dfs(node):
if not node:
return 0
left_sum = dfs(node.left)
right_sum = dfs(node.right)
# 处理当前节点(使用子树信息)
total = left_sum + right_sum + node.val
return total
这种方式的优势在于:
| 方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 颜色标记法 | O(N) | O(N) | 需要状态记录的遍历 |
| BFS | O(N) | O(N) | 层级相关、最短路径问题 |
| 自顶向下DFS | O(N) | O(H) | 路径相关计算 |
| 自底向上DFS | O(N) | O(H) | 子树聚合计算 |
深度很大的树使用递归DFS可能导致栈溢出。解决方案:
对于需要多次访问同一节点的问题,可以考虑:
特别注意以下边界情况:
在实际编码中,我习惯先写出基础case的处理逻辑,再逐步添加特殊情况的处理。测试时要特别注意各种极端情况的组合。