拓扑排序是一种有向图的排序。

结果是图中顶点的有序序列,这里假设是降序,那么序列中任意两个顶点vi>vj,如果在图中不存在从vj到vi的边,也就是排序的结果不与图中的顺序违背。

排序的思路就是BFS。

把整个图分为一层一层的结构,每一次输出一层,每一层层内的点的大小没有指定,所以可以按照任意顺序输出,但是层与层之间是有大小关系的,必须一致。

如果是找降序,那么这个思路转换为BFS就是,不断地寻找入度为0的点,放入一个队列Q,只要Q不为空,就拿出Q中的元素n,输出,然后删除n的临边,每删除一条就检测相邻的那个点是否也是入度为0,如果是,就加入到队列中,重复这个过程,直到队列为空。

如果Q为空了但是还没有遍历完所有的点,说明有环,不存在拓扑排序,否则存在。

如果想要升序排,那么上述过程就变为了不断寻找出度为0的点,思路不变。

下面是找降序的基于二维数组的代码:

public void topologySort(int[][] graph){
int n = graph.length;
List<Integer> r = new ArrayList<>();
Queue<Integer> nodes = new LinkedList<>();
//计算初始入度为0的点,存入nodes
for(int i = 0; i < n; i++){
boolean isAllZero = true;
for(int j = 0; j < n; j++){
if(graph[j][i] > 0){
isAllZero = false;
break;
}
}
if(isAllZero)
nodes.add(i);
}
while(!nodes.isEmpty()){
int node = nodes.poll();
r.add(node);
for(int i = 0; i < n; i++){
if(graph[node][i] > 0){
graph[node][i] = 0;
boolean isAllZero = true;
for(int j = 0; j < n; j++){
if(graph[j][i] > 0){
isAllZero = false;
break;
}
}
if(isAllZero)
nodes.add(i);
}
}
}
System.out.println(r);
}


当然如果对空间复杂度没有特别的要求,这里不需要每一次用到度的时候都去计算一次。可以用一个map存放每一个顶点的度,这个map可以在第一次的for循环里面构建好。

然后在后面的for里,每当删除一条边时,相邻的顶点的map值减去一,在查看这个相邻点是否度为0时,只需要查看map即可,不需要再去遍历全部的节点来得到度了,由On变为了O1.