定义
拓扑排序是一种特殊排序方式,是以有向无环图中结点依赖关系,将每个结点逐个排序,常见的用例比如Java Springboot的依赖注入机制。
拓扑排序只是对有向无环图的一种排序方式
- 有向无环图:图中任何结点无法通过若干边回到该结点
- 有向有环图:图中某个结点可以通过若干边回到该结点
拓扑排序实现
-
建图
建图的步骤是我们将结点依赖关系构建成以入度这个单位量化的图结构
入度:有向图中指向该结点的个数
举例: 图中A指向B, C指向B, C指向A。那么A的入度为1,B的入度为2,C的入度为0。
-
BFS遍历
与基本BFS遍历思路类似,首先先将入度为0也就是没有依赖关系的点放入队列,一直维护这个队列每一次取出一个值将这个值指向的结点入度减1,如果入度变为0就继续加入队列。
class Solution {
public boolean topoSort(int[][] dependencies) {
HashMap<Integer, Integer> indegree = new HashMap<>();
HashMap<Integer, List<Integer>> graph = new HashMap<>();
// 建图
for (int[] pre: dependencies) {
graph.putIfAbsent(pre[0], new ArrayList<>());
graph.get(pre[0]).add(pre[1]);
indegree.put(pre[0], indegree.getOrDefault(pre[0], 0));
indegree.put(pre[1], indegree.getOrDefault(pre[1], 0)+1);
}
// 入度为0 入队列
Queue<Integer> q = new LinkedList<>();
for (int c: indegree.keySet()) {
if (indegree.get(c)==0) {
q.offer(c);
}
}
// BFS 遍历
while (!q.isEmpty()) {
int dep = q.poll();
if (!graph.containsKey(dep)) continue;
for (int sub: graph.get(dep)) {
indegree.put(sub, indegree.get(sub)-1);
if (indegree.get(sub)==0 && !visited[sub]) {
visited[sub] = true;
q.offer(sub);
}
}
}
}
}
模版题目
代码如下:
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
HashMap<Integer, Integer> indegree = new HashMap<>();
HashMap<Integer, List<Integer>> graph = new HashMap<>();
for (int i=0; i<numCourses; i++) {
indegree.put(i, 0);
}
for (int[] pre: prerequisites) {
graph.putIfAbsent(pre[0], new ArrayList<>());
graph.get(pre[0]).add(pre[1]);
indegree.put(pre[0], indegree.getOrDefault(pre[0], 0));
indegree.put(pre[1], indegree.getOrDefault(pre[1], 0)+1);
}
// find indegree = 0
Queue<Integer> q = new LinkedList<>();
boolean[] visited = new boolean[numCourses];
for (int c: indegree.keySet()) {
if (indegree.get(c)==0) {
q.offer(c);
visited[c] = true;
}
}
int cnt = 0;
while (!q.isEmpty()) {
int course = q.poll();
cnt++;
if (!graph.containsKey(course)) continue;
for (int sub: graph.get(course)) {
indegree.put(sub, indegree.get(sub)-1);
if (indegree.get(sub)==0 && !visited[sub]) {
visited[sub] = true;
q.offer(sub);
}
}
}
return cnt==numCourses;
}
}