Appearance
图遍历
图遍历用于从一个起点出发访问可达顶点。Baseline 中需要完成 BFS、DFS 和拓扑排序。三者的关注点不同:BFS 按层推进,DFS 沿路径深入,拓扑排序处理有向依赖关系。
BFS:按距离分层访问
BFS 使用队列。先发现的顶点先处理,因此它会按“距离起点经过多少条边”逐层向外扩展。在无权图中,BFS 第一次访问到某个顶点时,经过的边数就是最少边数。
对应过程:
- 将起点
A入队,并立刻标记为已访问。 - 取出队首
A,把它加入访问序列。 - 按邻接表顺序发现
D、B、C,全部入队。 - 取出
D,第一次发现F。 - 取出
B,第一次发现E。 - 取出
C时,D和E已经被发现,因此不能重复入队。 - 继续处理
F,第一次发现G。 - 队列为空时结束。
实现 BFS 时,推荐在“入队时”标记已访问,而不是在“出队时”才标记。这样可以避免同一个顶点被多个前驱重复放入队列。
DFS:沿一条路径深入
DFS 可以用递归或显式栈实现。它从当前顶点出发,选择一个尚未访问的邻接点继续深入;当没有新的邻接点时,再回退到上一个顶点。
对应过程:
- 进入顶点
A,立即标记并写入访问序列,递归栈中只有A。 - 按
A的邻接点顺序先选择D,递归栈变为A, D。 - 从
D继续进入F,递归栈变为A, D, F。 - 从
F进入G;G没有未访问邻接点,随后开始连续回退。 G、F、D都返回后,控制权回到A,再检查A的下一个邻接点。A继续递归进入B。- 从
B递归进入E。 E的邻接点F已经访问过,因此跳过这条边并返回。- 回到
A后访问C;C指向的E和D都已经访问过,只做检查,不会再次递归。 - 递归栈清空后 DFS 结束,访问序列为
A D F G B E C。
DFS 的关键是“先标记,再递归”。如果图中存在环,晚标记会导致递归在环中反复进入同一批顶点。
拓扑排序:处理有向依赖
拓扑排序只适用于有向无环图。它输出一个顶点序列,使每条有向边 u -> v 中的 u 都出现在 v 前面。课程 Baseline 使用 Kahn 算法。
对应过程:
- 统计每个顶点的入度。
- 将所有入度为 0 的顶点放入队列。
- 取出一个入度为 0 的顶点并加入结果。
- 删除它的出边影响,使相邻顶点入度减 1;有些顶点需要等待多个前驱都输出后才会入队。
- 新出现的入度为 0 的顶点继续入队,例如
D和E会在C输出后同时变为 0。 - 若最终输出顶点数等于总顶点数,拓扑排序成功;否则说明图中有环。
遍历模块的输入输出
邻接表和邻接矩阵两个模块的公开输入格式一致:
text
case_count
vertex_count edge_count directed start
from to
...输出格式:
text
CASE 1
BFS ...
DFS ...
TOPO_OK 1
TOPO ...TOPO_OK 为 1 时,TOPO 后面是一种合法拓扑序;TOPO_OK 为 0 时,TOPO 为空。拓扑排序答案可能不唯一,只要每条有向边的前后关系正确即可。
调试重点
- 是否只访问从起点可达的顶点。
- 是否在入队或递归前及时标记已访问。
- 邻接表是否按加边顺序枚举邻接点。
- 邻接矩阵是否按顶点编号从小到大扫描邻接点。
- 拓扑排序是否能正确识别有向环。
运行与作业指导
本页对应邻接表与邻接矩阵中的 BFS、DFS、拓扑排序。完成相关 TODO 后,建议运行 make test-adj-list 和 make test-adj-matrix。
完整的 Baseline、Project、输入输出规范和报告要求见:运行与作业指导。