图的遍历算法
字数 2551 2025-10-29 11:32:31
图的遍历算法
好的,我们开始学习“图的遍历算法”。图的遍历是指按照某种规则,系统地访问图中的每一个顶点,并且每个顶点只被访问一次的过程。这是图论中最基础、最重要的算法类别之一,是解决许多图论问题的前提。
第一步:理解遍历的必要性与核心思想
想象一下,你进入了一个巨大的、房间之间由走廊连接的网络迷宫(图),你的任务是走遍每一个房间(顶点),但又不希望重复进入同一个房间。你需要一个系统性的策略来完成这个任务。这就是遍历算法要解决的问题。
遍历的核心思想是:
- 避免重复:确保每个顶点只被访问一次。
- 避免遗漏:确保所有顶点都被访问到。
- 记录状态:需要记录哪些顶点已经被访问过(通常使用一个名为
visited的数组或集合来实现)。
根据访问顶点的“策略”不同,主要分为两种经典的遍历算法:广度优先搜索和深度优先搜索。虽然它们是基础,但我们将深入探讨其实现细节、性质和应用。
第二步:广度优先搜索
广度优先搜索的策略是“由近及远”,类似于水波扩散或社交网络中好友层次的探索。
1. 算法过程详解:
- 初始化:从一个选定的起始顶点
s开始。将s标记为“已访问”,并将其放入一个队列中。队列是一种“先进先出”的数据结构。 - 循环过程:只要队列不为空,就重复以下步骤:
- 出队:从队列的头部取出一个顶点,我们称它为当前顶点
u。 - 访问:正式地“访问”这个顶点
u(例如,打印其值或进行其他计算)。 - 探索邻域:检查
u的所有未被访问过的邻接顶点。对于每一个这样的邻接顶点v:- 将
v标记为“已访问”。 - 将
v入队(放入队列的尾部)。
- 将
- 出队:从队列的头部取出一个顶点,我们称它为当前顶点
2. 关键性质与示例:
- 生成树:BFS 遍历过程中经过的边会构成一棵以起始顶点为根的树,称为 BFS 生成树。
- 最短路径:在无权图中,BFS 能天然地找出从起始顶点
s到所有其他可达顶点的最短路径(即边数最少的路径)。在 BFS 生成树中,从根s到任意顶点v的路径就是最短路径。 - 层级关系:顶点是按照距离起始顶点的边数(层级)由小到大依次被访问的。
假设有一个简单的图:A-B-C,A-D。从A开始BFS:
- 访问A,队列:[A]。
- 出队A,访问A的未访邻居B和D。标记并入队B、D。队列变为:[B, D]。
- 出队B,访问B。B的未访邻居是C。标记并入队C。队列变为:[D, C]。
- 出队D,访问D。D没有未访邻居。队列变为:[C]。
- 出队C,访问C。C没有未访邻居。队列空,结束。
访问顺序:A, B, D, C。
第三步:深度优先搜索
深度优先搜索的策略是“一路走到黑,再回头”,类似于走迷宫时沿着一条路一直走下去,直到死胡同再返回上一个岔路口。
1. 算法过程详解(递归版本,最直观):
- 初始化:从一个起始顶点
s开始。 - 递归函数
DFS(u):- 将顶点
u标记为“已访问”。 - 访问顶点
u。 - 遍历
u的所有邻接顶点v:- 如果
v未被访问过,则递归地调用DFS(v)。
- 如果
- 将顶点
2. 算法过程详解(迭代版本,使用栈):
- 初始化:从起始顶点
s开始。将s标记为“已访问”,并将其压入一个栈。栈是一种“后进先出”的数据结构。 - 循环过程:只要栈不为空,就重复以下步骤:
- 弹栈:从栈顶弹出一个顶点,作为当前顶点
u。 - 访问:访问顶点
u。 - 探索邻域:检查
u的所有未被访问过的邻接顶点。对于每一个这样的邻接顶点v:- 将
v标记为“已访问”。 - 将
v压栈。
- 将
- 弹栈:从栈顶弹出一个顶点,作为当前顶点
3. 关键性质与示例:
- 生成森林:DFS 遍历过程中经过的边会构成一棵树(如果图连通)或一个森林(多棵不相交的树),称为 DFS 生成森林。
- 时间戳:可以记录每个顶点被第一次访问(发现)的时间和完成对其所有邻居探索的时间。这对分析图的结构(如判断环、拓扑排序)非常有用。
- 分类边:在 DFS 生成森林中,边可以被分类为:
- 树边:遍历时经过的边,是生成森林的一部分。
- 回边:指向祖先顶点的边(可用于检测环)。
- 前向边:指向后代顶点的非树边。
- 交叉边:连接不同 DFS 树或同一棵树中无直系祖先关系的顶点的边(在无向图的DFS中不会出现交叉边)。
同样以图 A-B-C,A-D 为例,从A开始DFS(递归):
- 访问A,递归进入A的第一个邻居B。
- 访问B,递归进入B的邻居C。
- 访问C,C无未访邻居,递归返回到B。
- B无其他未访邻居,递归返回到A。
- A的下一个未访邻居是D,递归进入D。
- 访问D,D无未访邻居,递归返回到A。结束。
访问顺序:A, B, C, D。
第四步:对比与应用场景
| 特性 | 广度优先搜索 | 深度优先搜索 |
|---|---|---|
| 数据结构 | 队列 | 栈(递归调用栈或显式栈) |
| 遍历顺序 | 按距离起始点的层级 | 沿分支深入到底再回溯 |
| 空间复杂度 | 最坏情况 O( | V |
| 经典应用 | 无权图的最短路径、社交网络中的“度”分离、网络广播 | 检测环、拓扑排序、寻找连通分量、路径查找(不保证最短) |
第五步:进阶概念与变体
掌握了基本的BFS和DFS后,可以理解一些重要的变体和扩展:
- 连通分量:对于无向图,从一个未访问顶点开始执行一次BFS或DFS,所能访问到的所有顶点集合构成一个连通分量。重复此过程直到所有顶点被访问,即可找出图的所有连通分量。
- 双向BFS:当需要寻找两个特定顶点之间的最短路径时,可以同时从起点和终点开始BFS。当两个搜索的“波前”相遇时,路径即被找到。这在搜索空间巨大时能显著减少探索的顶点数量。
- 迭代深化DFS:结合了BFS和DFS的优点。它通过逐步增加深度限制来反复运行DFS,既具备了DFS的空间效率,又能像BFS一样按层搜索,常用于人工智能的搜索问题。
图的遍历算法是图论的基石,几乎所有复杂的图算法都在其基础上构建。理解它们的细微差别和适用场景至关重要。