【Java】拓扑排序

文章目录

  • 1.什么是拓扑排序
  • 2.java实现思路
  • 3.代码实现
  • 4.运行结果
    • 测试用例1(无环)
      • 输入
      • 输出
    • 测试用例2(有环)
      • 输入
      • 输出


1.什么是拓扑排序

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。
【Java】拓扑排序_第1张图片

B站学习链接:https://www.bilibili.com/video/BV1uf4y1U7DX?spm_id_from=333.1007.top_right_bar_window_history.content.click

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(无环)

【Java】拓扑排序_第2张图片

输入

8 10
2 5
2 4
2 3
1 3
1 8
3 4
8 7
4 7
4 6
5 6

输出

【Java】拓扑排序_第3张图片

测试用例2(有环)

输入

8 10
2 5
4 2
2 3
1 3
1 8
3 4
8 7
4 7
4 6
5 6

输出

【Java】拓扑排序_第4张图片

你可能感兴趣的:(java,算法,数据结构)