前言
给定一些边信息,要得到拓扑排序,得学会把图的物理结构做出来,再进行层序遍历。
一、课程表
二、拓扑排序
package everyday.graph;
import java.util.*;
// 课程表
public class CanFinish {
/*
给定了有向边,看是否能得到拓扑排序。
拓扑排序:1-构造图 + 入度数组;2-层序遍历即可;3-记录出队列的数量是否等于numCourses;
*/
public boolean canFinish(int numCourses, int[][] prerequisites) {
// 入度数组
int[] inDegree = new int[numCourses];
// 构建邻接表。
for (int[] prerequisite : prerequisites) {
addEdge(prerequisite[0], prerequisite[1]);
inDegree[prerequisite[0]]++;
}
return getNodeCount(inDegree) == numCourses;
}
public int getNodeCount(int[] inDegree) {
int numCourses = inDegree.length;
// 层序遍历
Queue<Integer> que = new ArrayDeque<>();
// 寻找入度为0的节点加入。
for (int i = 0; i < numCourses; i++) if (inDegree[i] == 0) que.add(i);
// 开始拓扑排序。
int count = 0;
while (!que.isEmpty()) {
int cur = que.poll();
// 记录出队列节点数。
++count;
// 撤销cur节点,让next节点的入度减一。
Set<Integer> nodes = graph.get(cur);
// bug1:nodes为null,是不可以这样循环的,这样nodes.会调迭代器,会出现空指针异常。
if (nodes == null) continue;
for (Integer node : nodes) {
if (--inDegree[node] == 0) que.add(node);
}
}
return count;
}
// 构建图的邻接表。
private void addEdge(int behind, int front) {
// 添加节点
addNode(behind);
addNode(front);
// 设置有向边
graph.get(front).add(behind);
}
// 填加节点
private void addNode(int node) {
if (!graph.containsKey(node)) graph.put(node, new HashSet<>());
}
// 用Map来作为邻接表的物理结构。
Map<Integer, Set<Integer>> graph = new HashMap<>();
}
总结
1)对于图问题,建图的物理结构 + 图的遍历是基础,需熟练掌握邻接表的建立 + DFS + BFS。
参考文献
[1] LeetCode 课程表