拓扑排序【模板】

解决拓扑排序之前要先认识什么是拓扑排序 :

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

解决步骤:

  1. 使用邻接表将顶点联系起来,辅助数组inDegree表示每个顶点的入度。
  2. 借助队列和计数器变量来判断该有向图是否有环:
    1. 将入度为零的顶点入队(也就是拓扑图第一个顶点)
    2. 取队首,遍历与之相邻的顶点,若该顶点入度减一后为零就将其入队
    3. 只要队列非空就循环操作,计算器循环加一,与顶点数比较是否相等
  3. 本题末尾也不能输出空格,因此输出拓扑序列时要加限制条件
     

重要注释:

  • list模拟邻接表

        使用每个元素为一个list容器模拟邻接表进行建图
        list[a]所对应的数组中存储着该顶点所指向的其他顶点
        inDegree数组代表每一个顶点的入度情况

  • 使用一个队列,初始时将所有入度为0的顶点全部入队,之后采用BFS的思想:

        依次取出队头元素并存入结果数组中,然后在邻接表中遍历该队头元素所指向的其他顶点,将这些顶点的入度全部减一,若减一后某顶点的入度变为0,则将该顶点进行入队操作,重复此步骤直至队列为空为止。

  • 设置一个用于判断图中是否存在环(是否可以得到拓扑序列)的计数器,在弹出队头元素后要将计数器加一,最后队列为空后,若计数器的值与顶点数相同,则说明图不存在环,可以得到拓扑序列。

 

import java.util.*;
public class Main{
    public static void main (String[] args){
        Scanner sc = new Scanner(System.in);
        String[] str = sc.nextLine().split(" ");
        int n = Integer.parseInt(str[0]);
        Graph graph = new Graph(n);
        while(sc.hasNextLine()){
            String[] line = sc.nextLine().split(" ");
            int u = Integer.parseInt(line[0]);//开始顶点、
            int v = Integer.parseInt(line[1]);
            //入度加1
            graph.inDegree[v-1]++;
            //u点增加出度(邻接链表)
            graph.list.get(u-1).add(v-1);    
        }
        if(graph.topologincalSort()){
            for(int num:graph.res){
                System.out.print(num+" ");
            }
        }else
            System.out.println("-1");
    }
}
class Graph{
    public int[] inDegree;
    ArrayList<ArrayList<Integer>> list = new ArrayList<>();
    public List<Integer> res = new ArrayList<>();
    public Graph(int n){
        inDegree = new int[n];
        for(int i=0;i<n;i++)
            list.add(new ArrayList<>());
    }
    public boolean topologincalSort(){
        int num = 0;
        Stack<Integer> stack = new Stack<>();
        for(int i = 0;i<inDegree.length;i++)
            if(inDegree[i] == 0)
                stack.push(i);
        while(!stack.isEmpty()){
            int u = stack.pop();
            res.add(u+1);
            int len = list.get(u).size();
            for(int i=0;i<len;i++){
                int v = list.get(u).get(i);
                inDegree[v]--;
                if(inDegree[v]==0)
                    stack.push(v);
            }
            list.get(u).clear();
            num++;
        }
        return num == inDegree.length; 
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值