1. 拓扑排序是将有向图G的所有顶点排成一个线性序列,使得对图G中的任意两个顶点u,v如果存在边u,v那么序列中u一定是在v的前面,这个序列有被称为是拓扑序列
所以拓扑排序是针对于有向图的,是用来判定有向图中是否存在环(深度优先搜索也可以判定有向图是否有环)
2. 拓扑排序的执行过程如下:
① 定义一个队列,并把所有入度为0的节点加入到队列中去
② 取出队首节点,输出,然后删除所有从它发出的边,并且令这些边到达的顶点的入度减1,判断某个顶点入度是否为0假如是0那么加入到队列中
③ 反复执行②操作直到队列为空,如果队列为空的时候入对的节点的数目恰好是N,说明拓扑排序成功否则拓扑排序失败,图是存在环的
3. 下面使用Java语言来完成编程过程:
① 首先需要解决图的存储方式的问题,这里我们选择使用邻接表的方式来存储图,可以声明一个集合数组,数组中的每一个元素都是一个集合,那么就可以模仿创建的链表了,数组的下标表示顶点的编号
② 由于需要记录节点的入度,所以需要额外建立一个数组来记录节点的入度,并且在程序读入图的时候就记录好每一个节点的入度
测试数据如下:
5
6
0 1
0 2
0 3
1 4
2 4
3 4
4. 具体的代码如下:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
public class Main {
static int n = 0;
static int edgesNum = 0;
static int inDegree[];
static int count = 0;
static List<Integer> graph [];
@SuppressWarnings("unchecked")
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("输入图中顶点的个数: ");
n = sc.nextInt();
inDegree = new int[n];
System.out.println("输入图中边的条数: ");
edgesNum = sc.nextInt();
//创建一个List数组
graph = new ArrayList[n];
for(int i = 0; i < n; i++){
//初始化每一个集合中元素
graph[i] = new ArrayList<Integer>();
}
System.out.println("输入图中边的起始顶点, 结束顶点和顶点之间的权值: ");
for(int i = 0; i < edgesNum; i++){
int u = sc.nextInt();
int v = sc.nextInt();
graph[u].add(v);
inDegree[v]++;
}
boolean res = topologicalSort();
if(res){
System.out.println("拓扑排序成功");
}else{
System.out.println("拓扑排序失败");
}
sc.close();
}
private static boolean topologicalSort() {
Queue<Integer> queue = new LinkedList<Integer>();
//检查入度为零的顶点
for(int i = 0; i < n; i++){
if(inDegree[i] == 0){
queue.add(i);
//System.out.println(i);
}
}
while(!queue.isEmpty()){
int u = queue.poll();
//输出拓扑排序序列
System.out.print(u + " ");
for(int i = 0; i < graph[u].size(); i++){
int v = graph[u].get(i);
inDegree[v]--;
if(inDegree[v] == 0)queue.add(v);
}
//记录访问过的节点的数目
count++;
}
if(count == n) return true;
return false;
}
}