拓扑排序 Topological Sort
2018-05-02 16:26:07
一、拓扑排序
有向无环图(Directed acyclic graph,DAG)必定存在拓扑排序;非DAG没有拓扑排序一说。
二、拓扑排序算法
通常拓扑排序算法可以在O(n)的时间复杂度完成,具体来说是O(V + E)。
下面以leetcode207为例来介绍拓扑排序算法。
问题描述:

问题求解:
方法一、BFS
使用BFS求解拓扑排序是非常直观和简单的。
维护每个节点的indegree数目,对于入度为0的进队列,将所有入度为0的出队,并更新它们的邻接节点的indegree,若indegree == 0,入队。
循环以上操作直到队列为空。
public boolean canFinish(int numCourses, int[][] prerequisites) {
List<Integer>[] graph = new List[numCourses];
int[] indegree = new int[numCourses];
for (int i = 0; i < numCourses; i++) graph[i] = new ArrayList<>();
for (int[] edge : prerequisites) {
int from = edge[1];
int to = edge[0];
graph[from].add(to);
indegree[to] += 1;
}
int cnt = 0;
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0) q.add(i);
}
while (!q.isEmpty()) {
int curr = q.poll();
cnt += 1;
for (int next : graph[curr]) {
indegree[next] -= 1;
if (indegree[next] == 0) q.add(next);
}
}
return cnt == numCourses;
}
方法二、DFS
使用DFS代码更为简洁。
实际就是给每个节点打上状态标签,如果访问到了正在访问的节点,那么必定存在环。
另外,我们需要一个访问完成的标签,避免重复访问已经访问过的节点。
public boolean canFinish(int n, int[][] edges) {
List<Integer>[] graph = new List[n];
for (int i = 0; i < n; i++) graph[i] = new ArrayList<>();
for (int[] e : edges) {
int from = e[1];
int to = e[0];
graph[from].add(to);
}
int[] state = new int[n];
for (int i = 0; i < n; i++) {
if (state[i] == 0 && !dfs(graph, i, state)) return false;
}
return true;
}
private boolean dfs(List<Integer>[] graph, int node, int[] state) {
state[node] = 1;
for (int next : graph[node]) {
if (state[next] == 2) continue;
if (state[next] == 1) return false;
if (!dfs(graph, next, state)) return false;
}
state[node] = 2;
return true;
}
三、拓扑排序应用
210. Course Schedule II
问题描述:

问题求解:
也是一条裸的拓扑排序题,相较于上一题,本题可以说是更纯粹的拓扑排序,因为不仅需要判环,还需要输出一个合法的解。当然,算法实现上也是两种思路,一是DFS,而是kahn算法。
DFS:
public int[] findOrder(int numCourses, int[][] prerequisites) {
int[] res = new int[numCourses];
List<Integer>[] graph = new List[numCourses];
for (int i = 0; i < numCourses; i++) graph[i] = new ArrayList<>();
for (int[] pair : prerequisites) {
graph[pair[1]].add(pair[0]);
}
int[] state = new int[numCourses];
Stack<Integer> s = new Stack<>();
for (int i = 0; i < numCourses; i++) {
if (state[i] == 0)
if (!dfs(graph, state, s, i)) return new int[0];
}
for (int i = 0; i < numCourses; i++) res[i] = s.pop();
return res;
}
private boolean dfs(List<Integer>[] g, int[] state, Stack<Integer> s, int i) {
if (state[i] == 2) return true;
if (state[i] == 1) return false;
state[i] = 1;
for (int node : g[i]) {
if (!dfs(g, state, s, node)) return false;
}
state[i] = 2;
s.push(i);
return true;
}
Kahn:
public int[] findOrder(int numCourses, int[][] prerequisites) {
int[] res = new int[numCourses];
int[] indegree = new int[numCourses];
List<Integer>[] graph = new List[numCourses];
for (int i = 0; i < numCourses; i++) graph[i] = new ArrayList<>();
for (int[] pair : prerequisites) {
graph[pair[1]].add(pair[0]);
indegree[pair[0]]++;
}
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0)
q.add(i);
}
int cnt = 0;
while (!q.isEmpty()) {
int p = q.poll();
res[cnt++] = p;
for (int node : graph[p]) {
if (--indegree[node] == 0) q.add(node);
}
}
if (cnt == numCourses) return res;
else return new int[0];
}
- 1203. Sort Items by Groups Respecting Dependencies
问题描述:



问题求解:
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
Map<Integer, Set<Integer>> group2items = new HashMap<>();
Map<Integer, Set<Integer>> group_g = new HashMap<>();
Map<Integer, Integer> g_indegree = new HashMap<>();
Map<Integer, Set<Integer>> item_g = new HashMap<>();
Map<Integer, Integer> i_indegree = new HashMap<>();
int num_of_groups = m;
for (int i = 0; i < group.length; i++) {
if (group[i] == -1) group[i] = num_of_groups++;
}
for (int i = 0; i < num_of_groups; i++) {
group2items.put(i, new HashSet<>());
group_g.put(i, new HashSet<>());
g_indegree.put(i, 0);
}
for (int i = 0; i < n; i++) {
item_g.put(i, new HashSet<>());
i_indegree.put(i, 0);
group2items.get(group[i]).add(i);
}
for (int to = 0; to < beforeItems.size(); to++) {
int to_group = group[to];
for (int from : beforeItems.get(to)) {
int from_group = group[from];
if (to_group == from_group) {
item_g.get(from).add(to);
i_indegree.put(to, i_indegree.get(to) + 1);
}
else {
if (!group_g.get(from_group).contains(to_group)) {
group_g.get(from_group).add(to_group);
g_indegree.put(to_group, g_indegree.get(to_group) + 1);
}
}
}
}
// check groups
List<Integer> groups = new ArrayList<>();
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < num_of_groups; i++) {
if (g_indegree.get(i) == 0) {
q.add(i);
groups.add(i);
}
}
while (!q.isEmpty()) {
int cur = q.poll();
for (int to : group_g.get(cur)) {
g_indegree.put(to, g_indegree.get(to) - 1);
if (g_indegree.get(to) == 0) {
q.add(to);
groups.add(to);
}
}
}
if (groups.size() != num_of_groups) return new int[0];
// check items
List<Integer> res = new ArrayList<>();
for (int g : groups) {
int num = 0;
q = new LinkedList<>();
for (int item : group2items.get(g)) {
if (i_indegree.get(item) == 0) {
q.add(item);
res.add(item);
num += 1;
}
}
while (!q.isEmpty()) {
int cur = q.poll();
for (int to : item_g.get(cur)) {
i_indegree.put(to, i_indegree.get(to) - 1);
if (i_indegree.get(to) == 0) {
q.add(to);
res.add(to);
num += 1;
}
}
}
if (num != group2items.get(g).size()) return new int[0];
}
int[] ret = new int[res.size()];
for (int i = 0; i < res.size(); i++) ret[i] = res.get(i);
return ret;
}
拓扑排序 Topological Sort的更多相关文章
- LeetCode编程训练 - 拓扑排序(Topological Sort)
拓扑排序基础 拓扑排序用于解决有向无环图(DAG,Directed Acyclic Graph)按依赖关系排线性序列问题,直白地说解决这样的问题:有一组数据,其中一些数据依赖其他,问能否按依赖关系排序 ...
- 算法与数据结构基础 - 拓扑排序(Topological Sort)
拓扑排序基础 拓扑排序用于解决有向无环图(DAG,Directed Acyclic Graph)按依赖关系排线性序列问题,直白地说解决这样的问题:有一组数据,其中一些数据依赖其他,问能否按依赖关系排序 ...
- 【数据结构与算法Python版学习笔记】图——拓扑排序 Topological Sort
概念 很多问题都可转化为图, 利用图算法解决 例如早餐吃薄煎饼的过程 制作松饼的难点在于知道先做哪一步.从图7-18可知,可以首先加热平底锅或者混合原材料.我们借助拓扑排序这种图算法来确定制作松饼的步 ...
- 拓扑排序 (Topological Sorting)
拓扑排序(Topological Sorting) 一.拓扑排序 含义 构造AOV网络全部顶点的拓扑有序序列的运算称为拓扑排序(Topological Sorting). 在图论中,拓扑排序(Topo ...
- [MIT6.006] 14. Depth-First Search (DFS), Topological Sort 深度优先搜索,拓扑排序
一.深度优先搜索 它的定义是:递归探索图,必要时要回溯,同时避免重复. 关于深度优先搜索的伪代码如下: 左边DFS-Visit(V, Adj.s)是只实现visit所有连接某个特定点(例如s)的其他点 ...
- 拓扑排序(Toposort)
摘自:https://blog.csdn.net/qq_35644234/article/details/60578189 <图论算法> 1.拓扑排序的介绍 对一个有向无环图(Direct ...
- [LeetCode] 207. 课程表(拓扑排序,BFS)
题目 现在你总共有 n 门课需要选,记为 0 到 n-1. 在选修某些课程之前需要一些先修课程. 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1] 给定课程总量 ...
- BFS (1)算法模板 看是否需要分层 (2)拓扑排序——检测编译时的循环依赖 制定有依赖关系的任务的执行顺序 djkstra无非是将bfs模板中的deque修改为heapq
BFS模板,记住这5个: (1)针对树的BFS 1.1 无需分层遍历 from collections import deque def levelOrderTree(root): if not ro ...
- 拓扑排序(三)之 Java详解
前面分别介绍了拓扑排序的C和C++实现,本文通过Java实现拓扑排序. 目录 1. 拓扑排序介绍 2. 拓扑排序的算法图解 3. 拓扑排序的代码说明 4. 拓扑排序的完整源码和测试程序 转载请注明出处 ...
随机推荐
- activemq 消息队列服务器
ActiveMQ 安装配置 更多 安装 前置条件:1)安装JDK:2)配置 JAVA_HOME 环境变量,确保 echo $JAVA_HOME 输出JDK的安装路径 下载:wget http://ww ...
- zw版【转发·台湾nvp系列Delphi例程】HALCON HomMat2dRotate1
zw版[转发·台湾nvp系列Delphi例程]HALCON HomMat2dRotate1 procedure TForm1.Button1Click(Sender: TObject);var img ...
- FAFU 1136 最长递增子序列
http://acm.fafu.edu.cn/problem.php?id=1136 根据dp建边,建边的时候记得判断如果原本数的大小就ok了 好久没在自家OJ上刷了 #include <ios ...
- javascript 的 事件类型(事件)
事件通常与函数配合使用,这样就可以通过发生的事件来驱动函数执行. 事件是文档或者浏览器窗口中发生的,特定的交互瞬间. 事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都 ...
- 访问Hsql .data数据库文件
一.Hsql简介: hsql数据库是一款纯Java编写的免费数据库,许可是BSD-style的协议. 仅一个hsqldb.jar文件就包括了数据库引擎,数据库驱动,还有其他用户界面操作等内容.下载地址 ...
- 教你如何构建异步服务器和客户端的 Kotlin 框架 Ktor
Ktor 是一个使用 Kotlin 以最小的成本快速创建 Web 应用程序的框架. Ktor 是一个用于在连接系统(connected systems)中构建异步服务器和客户端的 Kotlin 框架. ...
- NetSuite助力各行业企业快速发展
Oracle NetSuite今天发布了一系列全新技术创新,帮助各行各业企业提升收入.海外扩张以及赋能更多业务用户.最新推出的商务管理.财务管理和分析能力可协助企业利用NetSuite平台来超越客户预 ...
- python之路----初识面向对象(二)
类命名空间与对象.实例的命名空间 创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性 而类有两种属性:静态属性和动态属性 静态属性就是直接在类中定义的变量 动态属性就 ...
- 什么叫集群、分布式,分布式与集群有什么区别?(康神sf讲座学习笔记)
集群是物理形态,分布式是工作方式. 只要一堆机器放在那里,就是集群.比如Nginx后面的十台服务器,就是一个集群 分布式将任务放在多个物理隔离的节点上进行. 分布式中各个子节点互不通信,统一受管控中心 ...
- UVA12558 Egyptian Fractions (HARD version) (埃及分数,迭代加深搜索)
UVA12558 Egyptian Fractions (HARD version) 题解 迭代加深搜索,适用于无上界的搜索.每次在一个限定范围中搜索,如果无解再进一步扩大查找范围. 本题中没有分数个 ...