拓撲排序 - Topological Sort
有向圖的拓撲排序是它的頂點的線性排序,比如任意 邊 uv 對於 它的頂點 u 和 頂點 v, u v按照 u 在前 v在後的順序排序。 注意:只有 有向無環圖 (DAG) 才有拓撲排序, 如果一個圖 是有環 的圖那麼它不存在拓撲排序。
在現實生活中, 拓撲排序能被用於以下場景。 比如任意頂點都是要完成的任務,並且每個邊 都是 完成一個任務才能繼續完成下一個任務的 一種限制。 所以在這種情況下, 對這個圖的拓撲排序就是完成所有任務的序列佇列。
The graph shown to the left has many valid topological sorts, including:
|
Kahn's 演算法。演算法複雜度為 線性時間(邊的數 + 頂點的數)
L - 一個空的list,作為最後返回值
S - 一個Set包含所有的點,這些點沒有incoming 的邊。
while S is non-empty do:
remove a node n from S
add n to the list of L
for each node m with an edge e from n to m do:
remove edge e from graph
if m has no other incoming edges then:
insert m into S
if graph has edges then:
return error ( 有環圖,不能進行拓撲排序 )
else
return L ( 解 )
Java 版本實現
package TopologicalSorting;
import java.util.*;
//this indicate an edge
//from node_2 point to node_1
class Pair {
String node_1;
String node_2;
Pair(String node_1, String node_2) {
this.node_1 = node_1;
this.node_2 = node_2;
}
}
public class KahnAlgorithm {
public static ArrayList<String> Kahn (ArrayList<Pair> graph) {
ArrayList<String> L = new ArrayList<String> (); //to store the result
ArrayList<String> S = new ArrayList<String> (); //set of nodes with no incoming edges
S = findNoIncomingEdges (graph);
while (!S.isEmpty()) {
String n = S.remove(0); //remove node n from S
L.add(n); //add node n to L
//find all of the nodes that have an edge from n to m
for (String m : findNodes (n,graph)) {
//remove edge e from graph
graph = removeEdge (m, n, graph);
//if m does not has incoming edge
if (!hasIncomingEdge(m, graph)) {
//insert m into S
S.add(m);
}
}
}
//still has edge left
if (!graph.isEmpty()) {
return null;
}
return L;
}
//find the nodes with no incoming edge
public static ArrayList<String> findNoIncomingEdges (ArrayList<Pair> graph) {
ArrayList<String> result = new ArrayList<String> ();
Set<String> grandSet = new HashSet<String> (); //all node in graph
//construct grand set
for (Pair temp : graph) {
grandSet.add(temp.node_1);
grandSet.add(temp.node_2);
}
result.addAll(grandSet);
for (Pair temp : graph) {
if (grandSet.contains(temp.node_1)) {
result.remove(temp.node_1);
}
}
return result;
}
//find the nodes and remove all of the edges with n and m
public static ArrayList<String> findNodes (String n, ArrayList<Pair> graph) {
ArrayList<String> result = new ArrayList<String> ();
//find the nodes that point from n to m
for (Pair p : graph) {
if (p.node_2.compareTo(n) == 0) {
result.add(p.node_1);
}
}
return result;
}
//remove edge from graph
public static ArrayList<Pair> removeEdge (String m, String n, ArrayList<Pair> graph) {
ArrayList<Pair> result = new ArrayList<Pair> ();
result = (ArrayList<Pair>) graph.clone();
for (Pair temp : graph) {
if (temp.node_1.compareTo(m) == 0
&& temp.node_2.compareTo(n) == 0) {
result.remove(temp);
}
}
return result;
}
//check whether it has incoming edge
public static boolean hasIncomingEdge (String m, ArrayList<Pair> graph) {
for (Pair temp : graph) {
if (temp.node_1.compareTo(m) == 0) {
return true;
}
}
return false;
}
}
有問題歡迎指出。
相關文章
- 拓撲排序排序
- 拓撲排序,YYDS排序
- 拓撲排序模板排序
- 拓撲排序 POJ2367Genealogical tree[topo-sort]排序
- 拓撲排序小結排序
- 圖論——拓撲排序圖論排序
- 筆記:拓撲排序筆記排序
- AOV網與拓撲排序排序
- Reward (圖論+拓撲排序)圖論排序
- 拓撲排序核心程式碼排序
- HDU 4857 逃生(拓撲排序)排序
- 拓撲排序就這麼回事排序
- HDU4857逃生(拓撲排序)排序
- 紙上談兵: 拓撲排序排序
- poj 1094 拓撲排序排序
- 有向圖的拓撲排序——DFS排序
- poj1094 拓撲排序排序
- 圖解拓撲排序+程式碼實現圖解排序
- 【圖論】拓撲排序+優先佇列圖論排序佇列
- POJ 3249-Test for Job(拓撲排序&&DP)排序
- HDU 5438 Ponds (拓撲排序應用+DFS)排序
- CF 274D Lovely Matrix(拓撲排序)排序
- HDU 4857-逃生(反向拓撲排序-按條件排序)排序
- 圖的拓撲排序詳解與實現排序
- 圖(3)--拓撲排序與關鍵路徑排序
- hdu 1811 並查集+拓撲排序並查集排序
- VOL.2 拓撲排序與關鍵路徑排序
- POJ1094[有向環 拓撲排序]排序
- csdn hud 2094 拓撲排序 已經AC排序
- 拓撲排序詳解(梅開二度之dfs版按字典序輸出拓撲路徑+dfs版輸出全部拓撲路徑排序
- 洛谷P3953 逛公園(dp 拓撲排序)排序
- HDU1285確定比賽名次(拓撲排序)排序
- Day2 尤拉路,拓撲排序和差分約束排序
- CF798E. Mike and code of a permutation [拓撲排序 線段樹]排序
- 排序sort排序
- Sort排序排序
- 【BZOJ-1565】植物大戰殭屍 拓撲排序 + 最小割排序
- POJ1270 Following Orders[拓撲排序所有方案 Kahn]排序