有向圖的拓撲排序是它的頂點的線性排序,比如任意 邊 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;
}
}
有問題歡迎指出。