1、算法描述
假设G=(V,E)是一个具有n个顶点的有向图,V中顶点序列vl,v2,…,vn称做一个拓扑序列(Topological Order),当且仅当该顶点序列满足下列条件:若在有向图G中存在从顶点vi到vj的一条路径,则在顶点序列中顶点vi必须排在顶点vj之前。
操作步骤:
(1)、在网络中选一个没有直接前驱的顶点,并输出。
(2)、从图中删去该顶点, 同时删去所有它发出的有向边。
(3)、重复以上步骤,直到剩余的网中不再存在没有前趋的顶点为止。
2、图例
![](https://img-my.csdn.net/uploads/201210/08/1349685547_3759.jpg)
3、代码
public static void main(String[] args) {
TopuSort topu = new TopuSort();
Graph graph = topu.new Graph(20);
for (char c : "abcdefghijklmnopq".toCharArray()) {
graph.add(c);
}
graph.connect(0, 2);
graph.connect(0, 5);
graph.connect(0, 7);
graph.connect(0, 8);
graph.connect(0, 10);
graph.connect(0, 14);
graph.connect(1, 2);
graph.connect(2, 6);
graph.connect(3, 12);
graph.connect(15, 3);
graph.connect(11, 7);
graph.connect(4, 12);
graph.connect(12, 10);
graph.connect(16, 14);
graph.initNoFatherNode();
Node[] nodes = topu.sort(graph);
System.out.println(Arrays.toString(nodes));
}
public Node[] sort(Graph graph) {
Node[] nodes = new Node[graph.currentLength];
int index = 0;
int pos = 0;
while (graph.currentLength > 0) {
index = graph.findOneNoFatherNode(); // 找到第一个没有后继的节点
assert index != -1 : "图中存在环";
nodes[pos++] = graph.nodes[index]; // 放入结果中
graph.removeNode(index); // 从图中把它删除
}
return nodes;
}
class Node {
private final Object value;
private int precNums = 0;
// 后缀节点位置
private final List<Integer> suffixs = new ArrayList<Integer>();
public Node(Object value) {
super();
this.value = value;
}
public Object getValue() {
return value;
}
@Override
public String toString() {
return "Node [value=" + value + "]";
}
}
class Graph {
private final Node[] nodes;
private int currentLength;
private final int length;
// 存放没有前驱的位置
private final Set<Integer> set = new HashSet<Integer>();
public Graph(int length) {
super();
this.currentLength = 0;
this.length = length;
nodes = new Node[length];
}
void add(Object value) {
assert currentLength <= nodes.length;
nodes[currentLength++] = new Node(value);
}
void connect(int from, int to) {
assert from < length;
assert to < length;
nodes[to].precNums++;
nodes[from].suffixs.add(to);
}
void removeNode(int index) {
for (int i : nodes[index].suffixs) {
nodes[i].precNums--;
if (nodes[i].precNums == 0) {
set.add(i);
}
}
nodes[index] = null;
currentLength--;
set.remove(index);
}
void initNoFatherNode() {
for (int i = 0; i < length; i++) {
if (null != nodes[i] && nodes[i].precNums == 0) {
set.add(i);
}
}
}
int findOneNoFatherNode() {
for (int j : set) {
if (null != nodes[j] && nodes[j].precNums == 0) {
return j;
}
}
return -1;
}
}
PS:拓扑排序可以用来判断一个图是否有环,如果图经过拓扑排序后没有剩余的节点,那就是无环图,否则是有环图。