有向图的拓扑排序是它的顶点的线性排序,比如任意 边 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;
}
}
有问题欢迎指出。