Java实现有向图的拓扑排序

1.拓扑排序

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

2.实现方法

利用二维数组保存有向图,重复边过滤,有边的话map[i][j]=1,i到j存在着边,用一个indegree数组保存每个节点的入度信息,

从度为0的节点开始,入栈,若栈不为空,出栈,当前元素到其他元素若存在边,去除这条边,map[i][j]=0,此外,让边的末尾节点入度减1,若减为0,则重新入栈,并且将此顶点入度去掉

3.代码实现

package 有向图的拓扑排序;

import java.util.ArrayList;
import java.util.Scanner;
import java.util.Stack;

/**
 * @Author:likui
 * @PacakgeName:test
 * @Description: 拓扑排序
 * 3 1 5 21 10  孩子节点
 * 0 3 3 1 5   父节点
 * 3           指定节点
 * @Date:Created in 9:04 2019/9/7
 */

public class Main {

    public static void way(int []x,int y[],int pos,int max){
        int indegree[]=new int[max];//保存每个顶点的入度信息
        int map[][]=new int[max][max];//保存整个有边的图
        for (int i = 0; i <x.length ; i++) {
            if (x[i]==0||y[i]==0)//去掉顶点为0的输入,过滤条件
                continue;
            else
            {
                if (map[x[i]-1][y[i]-1]==0){//保存边,重复边去掉,map[i][j]=1,说明有i到j的有向边
                    map[x[i]-1][y[i]-1]=1;
                    indegree[y[i]-1]++;
                }
            }
        }
        System.out.println("拓扑排序结果:");
        System.out.println(BFS(indegree,map,pos));
    }

    private static ArrayList<Integer> BFS(int []indegree,int[][] map,int pos) {
        ArrayList<Integer> list=new ArrayList<>();//保存拓扑排序
        Stack<Integer> stack = new Stack<>();
        //indegree[pos-1]=-1; //从指定位置开始进行拓扑排序
        for (int i = 0; i <map.length ; i++) {//去掉没有边的节点的图
            for (int j = 0; j <map.length ; j++) {
                if (map[i][j]!=0&&indegree[i]==0&&i==pos-1)
                {
                    stack.push(i);//将入度为0的节点入栈
                    indegree[i] = -1;
                }
            }
        }
     /*   for (int i = 0; i < indegree.length; i++) {//整个图的拓扑排序,包含没有边的节点
            if (indegree[i] == 0) {
                 stack.push(i);
                indegree[i] = -1;
            }
        }*/
        while (!stack.isEmpty()) {//若栈不为空
            int p = stack.pop();//出栈
           // count++;
            list.add(p+1);//访问当前元素
            for (int j = 0; j < indegree.length; j++) {
                if (map[p][j] == 1) {//当前度为0的节点到其他顶点有边
                    map[p][j] = 0;//去掉这条边
                    indegree[j]--;//变得末尾节点入度减1
                    if (indegree[j] == 0) {//如果度减为0,入栈
                        stack.push(j);
                        indegree[j] = -1;//没有入度信息
                    }
                }
            }
        }
        return list;
    }
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        String s1=sc.nextLine();
        String s2=sc.nextLine();
        int pos=Integer.parseInt(sc.nextLine());
        String str1[]=s1.split(" ");
        String str2[]=s2.split(" ");
        int x[]=new int[str1.length];
        int y[]=new int[str2.length];
        int max1=Integer.MIN_VALUE;
        int max2=Integer.MIN_VALUE;
        for (int i = 0; i <x.length ; i++) {
            x[i]=Integer.parseInt(str2[i]);
            y[i]=Integer.parseInt(str1[i]);
            max1=Math.max(y[i],max1);
            max2=Math.max(x[i],max2);
        }
        max1=Math.max(max1,max2);
        way(x,y,pos,max1);
    }

}

4.输出测试用例结果,0代表不存在的节点

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值