1.什么是拓扑排序
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。
2.java实现思路
主要需要新建以下几个变量:
public static int vertexNum; //顶点数目
public static int arcNum; //边数目
public static int[][] arr; //图的邻接表
public static int[] inDegree; //记录每个定点的入度
public static ArrayList<Integer> ans = new ArrayList<>(); //存放拓扑排序的结果
其中,需要维护一个inDegree数组,该数组用来存放每一个顶点的入度。
拓扑排序的主要思路如下:
找到当前入度为0的点
1.把该点加入到ans答案数组中
2.把该点所关联的边的入度都减去1
3.设置该点的入度为-1,表明该点已经被放入到ans数组中
3.代码实现
package test;
import java.util.ArrayList;
import java.util.Scanner;
public class _01拓扑排序 {
public static int vertexNum; //顶点数目
public static int arcNum; //边数目
public static int[][] arr; //图的邻接表
public static int[] inDegree; //记录每个定点的入度
public static ArrayList<Integer> ans = new ArrayList<>(); //存放拓扑排序的结果
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
vertexNum = sc.nextInt();
arcNum = sc.nextInt();
sc.nextLine();
arr = new int[vertexNum+1][vertexNum+1];
inDegree = new int[vertexNum+1];
int vertex1,vertex2;
for(int i = 0 ; i < arcNum ; i++) {
vertex1 = sc.nextInt();
vertex2 = sc.nextInt();
sc.nextLine();
arr[vertex1][vertex2] = 1;
}
//初始化inDegree数组。计算每个顶点的入度,并把结果存到inDegree数组里面
int rudu = 0;
for(int j = 1 ; j < vertexNum+1 ; j++) {
for(int i = 1 ; i < vertexNum+1 ; i++) {
if(arr[i][j] == 1) {
rudu++;
}
}
inDegree[j] = rudu;
rudu = 0;
}
//输出有向图
System.out.println("该图的邻接矩阵表示为:");
for(int i = 1 ; i < vertexNum+1 ; i++) {
for(int j = 1 ; j < vertexNum+1 ; j++) {
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
TopoSort();
}
public static void TopoSort() {
// 找到当前入度为0的点
// 1.把该点加入到ans答案数组中
// 2.把该点所关联的边的入度都减去1
// 3.设置该点的入度为-1,表明该点已经被放入到ans数组中
int vertexfound = findIndegreeZero();
//只要还存在入度为0的点,就进行while循环
while(vertexfound != -1) {
ans.add(vertexfound);
inDegree[vertexfound] = -1;
for(int j = 1 ; j < vertexNum+1 ; j++) {
if(arr[vertexfound][j] > 0) {
inDegree[j] --;
}
}
vertexfound = findIndegreeZero();
}
//输出拓扑排序的结果
if(ans.size() < vertexNum) {
//存在环
System.out.println("该图存在环");
}
else {
System.out.println("拓扑排序的结果是:");
for(int i = 0 ; i < ans.size() ; i ++) {
System.out.print(ans.get(i)+" ");
}
}
}
/**
* 找到入度为0的点
* @return 如果存在入度为0的点,则返回这个点;如果不存在,则返回-1
*/
public static int findIndegreeZero() {
for(int i = 1 ; i < vertexNum+1 ; i++) {
if(inDegree[i] == 0) {
return i;
}
}
return -1;
}
}
4.运行结果
测试用例1(无环)
输入
8 10
2 5
2 4
2 3
1 3
1 8
3 4
8 7
4 7
4 6
5 6
输出
测试用例2(有环)
输入
8 10
2 5
4 2
2 3
1 3
1 8
3 4
8 7
4 7
4 6
5 6