Java实现拓扑排序

拓扑排序的介绍:

  • 拓扑排序:将有向图中的顶点以线性方式进行排序。即对于任何自顶点u到顶点v的有向边u->v ,在最后的排序结果中,顶点u总是在顶点v的前面。这样的排序结果,称为拓扑序。
  • 有环图,不存在拓扑排序。
  • 对于一个有向图,可能有多个拓扑排序的结果。
  • 如下图的拓扑排序有两种情况:
    1->2->3->4->5
    1->2->3->5->4

在这里插入图片描述

拓扑排序的代码实现:

要实现拓扑排序的有向图:
在这里插入图片描述

实现思路:

  • 将有向图转化为邻接矩阵,方便查找两个点之间是否有箭头。
  • 首先遍历每一个顶点,尝试以每一个顶点为起点开始进行深搜,到深搜到最底层,也就是当碰到一个没有出度的顶点时,则这个顶点肯定是可以放在最后的,这时我们将这个顶点放到数组末尾(压栈)。
  • 在深搜的过程中要标记,标记有三种:0表示还没有深搜过的顶点,1表示已经进行过深搜并且已经放入数组中(压栈),-1表示当前深搜正在遍历的顶点。之所以添加第三种标记-1是为了在深搜的过程中判断是否出现有环图。

Java代码:

public class 拓扑排序 {
	//用临街矩阵表示有向图
	private static int[][] grash = {
		{0,1,0,0},
		{0,0,0,0},
		{0,1,0,0},
		{0,0,1,0}
	};
	//标记访问状态,1:已经访问并返回,0:从未被访问, -1:正在访问
	private static int[] visit = new int[4]; 
	private static char[] v = {'a','b','c','d'}; //顶点内容
	private static int n = 4;  //顶点的个数
	private static int[] topo = new int[n]; //拓扑排序的结果
	private static int t = n; //标记topo数组到了哪一位 
	
	public static void main(String[] args) {
		for(int i=0; i<n; i++){
			if(visit[i]==1){//  以访问过则跳过
				continue;
			}
			if(!dfs(i)){
				System.out.println("有向图存在环,不存在拓扑排序");
			}
		}
		
		//打印排序后的结果
		for(int i=0; i<n; i++){
			System.out.print(v[topo[i]] + " ");
		}
	}

	//深搜遍历,返回false表示存在环,不存在拓扑排序
	private static boolean dfs(int i) {
		visit[i] = -1;  //标记此次深搜访问过的顶点
		
		//尝试寻找与其他顶点的有向边(是否有出度)
		for(int j=0; j<n; j++){
			if(grash[i][j]>0){  //顶点i到j右箭头
				
				if(visit[j]==-1){
					//此处,关于顶点j的递归还没有退出,前驱的状态是-1,后继的状态也是-1,
					//说明在此次递归中早就路过了j,现在是第二次路过j
					//一次递归路过两次同一顶点,只有一种情况,形成了环,所以返回false
					return false;
				}
			/*	if(visit[j]==0){//这样写不行,因为不能在没有进行标记的情况下return true
					return dfs(j); 
				}   */
				if(visit[j]==0 && dfs(j)==false)
					return false;
			}
		}
		
		//如果没有出度则将顶点放入数组
		topo[--t] = i;
		visit[i] = 1;
		return true;
	}
}

猜你喜欢

转载自blog.csdn.net/HC199854/article/details/106641368
今日推荐