交互式图论学习
交互式图论学习
Guest User
Using app without sign in
交互式深度优先搜索可视化工具
沿着每个分支尽可能深入探索,然后回溯
选择算法并生成步骤以开始可视化
深度优先搜索(DFS)是一种图遍历算法,沿每条分支尽可能深入后再回溯。从源节点出发,它沿一条路径走到死胡同,然后退回到最近的分叉点,尝试下一条尚未探索的边,通常用递归或显式栈实现。
DFS 先标记起始节点为已访问,然后递归访问第一个未访问的邻居,每步都往更深处走。当某节点没有未访问的邻居时,递归回退,从上一个节点继续搜索。每个节点和每条边都恰好处理一次,时间为 O(V + E),空间为 O(V)。节点进入和离开递归的顺序产生发现时间和完成时间,被许多派生算法所用。
DFS 是拓扑排序、环检测、强连通分量、割点、桥以及迷宫生成的基础。在实践中,它支撑构建工具的依赖解析、死锁检测和谜题求解器。面试官在回溯、网格中的岛屿以及路径枚举类问题中大量使用 DFS。
DFS 通常写成递归形式,但迭代写法把栈显式化,可避免在深图上撑爆调用栈。两者产生相同的发现顺序。
DFS(图, 源点):
时间 = 0
访问(源点)
访问(u):
已访问.加入(u)
disc[u] = ++时间 // 发现时间
对 u 的每个邻居 v:
若 v 不在已访问中:
父结点[v] = u
访问(v)
fin[u] = ++时间 // 完成时间发现时间与完成时间才是 DFS 真正的产物。后代的区间 [disc[u], fin[u]] 严格嵌套在其祖先的区间之内,而这种嵌套性正是拓扑排序、环检测、Tarjan 强连通分量、割点与桥的共同基础。
从 A 出发在可视化工具默认加载的图上运行 DFS,邻居始终按字母顺序选取。
示例图: 无向边 A-B (2)、A-C (3)、B-C (1) 和 C-D (4)。DFS 忽略权重。
遍历顺序是 A、B、C、D。BFS 恰好也以同样顺序访问这四个结点,但生成的树不同:BFS 得到扁平的树 A 到 B、A 到 C、C 到 D,而 DFS 得到单链 A 到 B 到 C 到 D。回边 C 到 A 标出了环 A-B-C-A,嵌套区间 A[1,8]、B[2,7]、C[3,6]、D[4,5] 直接反映了递归深度。
时间: O(V + E) · 空间: O(V)
每个结点恰好被访问一次,因为已访问检查守住了递归调用;每条边从两个端点各被检查一次,无向图中共 2E 次,有向图中为 E 次。空间是已访问集合加递归栈,均为 O(V)。递归深度等于最长简单路径的长度,因此在一条百万结点的链上,大多数语言中递归实现都会撑爆调用栈,此时必须改用显式栈的写法。
问题关乎结构时选 DFS,关乎距离时选 BFS。
| 替代算法 | 以下情况更合适 | 代价 |
|---|---|---|
| BFS | 你要的是最少跳数或按层遍历,或图很深而答案很可能靠近源点。 | O(V + E) |
| 迭代加深搜索 | 图实际上无限或极深,而你仍想要最浅的解,又不愿承担 BFS 的内存开销。 | O(b^d) |
| Tarjan 强连通分量 | 你要的正是有向图的强连通分量。它就是 DFS 加上一次遍历内的 low-link 记账。 | O(V + E) |
| 并查集 | 你只需要无向图的连通分量,且边是逐条到达的。 | 近似 O(E) |