📚 DFS & BFS 核心学习笔记
一句话总结:BFS是"广撒网"逐层推进,DFS是"深挖掘"一条路走到黑
🎯 核心思想对比
BFS - 广度优先搜索
🌊 水波纹扩散法:先近后远,逐层推进
- 口号:"一圈一圈往外荡"
- 数据结构 :队列
Queue(FIFO) - 比喻:往池塘扔石头,波纹一圈圈扩散
DFS - 深度优先搜索
🪜 楼梯下潜法:一路向下,不撞南墙不回头
- 口号:"一条路走到黑"
- 数据结构 :栈
Stack(LIFO) 或 递归 - 比喻:走迷宫,选一条路一直走,走不通再回溯
📊 可视化遍历顺序
图结构:
A
/|\
B C D
|
E
| 搜索类型 | 访问顺序 | 特点 |
|---|---|---|
| BFS | A → B → C → D → E | 先访问完所有直接邻居 |
| DFS | A → B → E → C → D | 沿一条路径深入到底 |
💾 空间复杂度对比
BFS - 横向膨胀
python
# 最坏情况:存储整层节点
Queue = [A, B, C, D, E, ...] # 可能指数级增长
- 复杂度:O(最大宽度)
- 树形图:最坏 2^h (h=深度)
- 优点:适合稀疏图
DFS - 纵向深入
python
# 只需存储当前路径
Stack = [A, B, E] # 最多深度个节点
- 复杂度:O(最大深度)
- 树形图:最坏 h (h=深度)
- 优点:通常更省内存
🎪 经典应用场景
✅ BFS 擅长
| 场景 | 原因 |
|---|---|
| 最短路径 | 天然一层=一步,保证最短 |
| 橘子腐烂 | 每分钟感染一层,精准计时 |
| 社交网络 | "六度人脉"找最短关系链 |
| 地图导航 | 寻找最少换乘/最短距离 |
✅ DFS 擅长
| 场景 | 原因 |
|---|---|
| 环检测 | 深度递归,撞环即返 |
| 连通分量 | 一次遍历标记所有相连节点 |
| 拓扑排序 | 深度优先完成依赖 |
| 回溯问题 | 全排列、子集天然适合递归 |
💻 代码模板速查
BFS 模板(橘子腐烂风格)
python
from collections import deque
def bfs(start):
queue = deque([start])
visited = set([start])
while queue:
node = queue.popleft() # 关键:先进先出
for neighbor in node.neighbors:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
DFS 模板(课程依赖风格)
python
# 递归版(最常用)
def dfs(node, visited, path):
if node in path: # 检测环
return True
if node in visited:
return False
visited.add(node)
path.add(node)
for neighbor in node.neighbors:
if dfs(neighbor, visited, path):
return True
path.remove(node)
return False
# 迭代版(避免递归深度限制)
def dfs_iterative(start):
stack = [start]
visited = set()
while stack:
node = stack.pop() # 关键:后进先出
if node not in visited:
visited.add(node)
for neighbor in node.neighbors:
stack.append(neighbor)
🎯 选型决策树
问题:需要找"最短路径/最少步数"?
├─ 是 → BFS
└─ 否 → 继续判断
问题:需要检测"是否有环"?
├─ 是 → DFS
└─ 否 → 继续判断
问题:空间是否紧张?
├─ 是 → DFS
└─ 否 → 两者皆可,看实现偏好
🧠 记忆口诀
BFS 口诀
队列先进先出,一层一层剥开
波纹扩散自然,最短路径首选
DFS 口诀
栈或递归实现,深度优先挖掘
一条路走到黑,环检测神器
⚡ 快速对比表
| 特性 | BFS | DFS |
|---|---|---|
| 顺序 | 横向逐层 | 纵向深入 |
| 空间 | O(宽度) | O(深度) |
| 最短路径 | ✅ 保证 | ❌ 不保证 |
| 环检测 | ⚠️ 可以但繁琐 | ✅ 天然适合 |
| 实现 | 队列迭代 | 递归/栈 |
| 适用 | 距离、层级 | 连通、环、回溯 |
💡 实战技巧
- 看到"最短"想BFS:最少步数、最少时间、最少操作
- 看到"环"想DFS:检测循环依赖、死锁
- 空间爆炸用DFS:图很宽但不深时
- 递归太深用BFS:避免栈溢出
- 多源起点:BFS可天然多起点同时开始(如橘子腐烂)
最后提醒 :两者时间复杂度都是 O(V+E),选型关键看问题需求 和空间限制!