一、拓扑排序基础
1.1 有向无环图(DAG)
有向无环图是指一个没有回路的有向图。简单来说,如果无法从某个顶点出发经过若干条边回到该点,那么这个图就是 DAG。

1.2 AOV 网:顶点活动图
在 DAG 的基础上,我们用顶点表示活动,用边表示活动执行的先后顺序。

1.3 什么是拓扑排序
拓扑排序的目标是找到做事的先后顺序。核心逻辑是:每次找出入度为 0 的点,将其加入结果序列,并删除该点相连的边,重复此过程直到所有点都被处理或发现环路。
1.4 基于 BFS 的实现思路
借助队列进行广度优先搜索(BFS)是实现拓扑排序的高效方式:
- 初始化:将所有入度为 0 的点加入队列。
- 循环处理:当队列不为空时,取出队头元素加入最终结果。
- 更新依赖:删除与该点相连的边(即减少相邻点的入度)。
- 入队判断:若某相邻点的入度变为 0,则将其加入队列。
二、LeetCode 207. 课程表
题目要求判断是否能完成所有课程的学习。给定课程总数和先修课程关系数组,我们需要验证是否存在合法的拓扑排序。
解题思路
使用邻接表 List<List<Integer>> 表示图结构,下标对应课程 ID,数组内容指向的课程即为依赖关系。遍历先修数组构建图的同时统计每个课程的入度。随后执行一次 BFS 即可判断可行性。
注意细节:
- 每个点只能入队一次,避免重复计算。
- 若先修数组为空,直接返回 true。
代码实现
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
int m = prerequisites.length;
if (m == 0) return true;
// 建图
List<List<Integer>> edges = <>();
( ; i < numCourses; i++) {
edges.add( <>());
}
Queue<Integer> queue = <>();
[] inDegree = [numCourses];
[] visited = [numCourses];
( ; i < m; i++) {
edges.get(prerequisites[i][prerequisites[i].length - ]).add(prerequisites[i][]);
inDegree[prerequisites[i][]]++;
}
( ; i < numCourses; i++) {
(inDegree[i] == ) {
queue.add(i);
visited[i] = ;
}
}
(queue.isEmpty()) ;
(!queue.isEmpty()) {
queue.poll();
( neighbor : edges.get(tmp)) {
inDegree[neighbor]--;
}
( ; i < numCourses; i++) {
(inDegree[i] == && !visited[i]) {
queue.add(i);
visited[i] = ;
}
}
}
( ; i < numCourses; i++) {
(inDegree[i] != ) ;
}
;
}
}


