拓扑排序讲解和典型例题

拓扑排序应用:拓扑排序是应用在有向图中,对所有的节点进行排序。

思路:

1.首先统计所有节点的入度,把其加入一个入度表中;

2.维护一个队列,讲入度为0的节点入队;并且维护一个邻接表用于存储每个节点相关联的节点入度数量;

3.然后将对列中的节点出队,并且将与这个节点相关联的节点入度减一。如果此时有相关的节点入度为0,则入 队。

4.如果最后都是入度为0的节点,则表示有拓扑排序;如果最后不存在入度为0的节点,则表示图有环,不存在拓扑排序。

如下图所示:(这个图借用了这篇博客:原文链接:https://blog.csdn.net/qq_41713256/article/details/80805338

 

典型例题讲解

207. 课程表

这个题目中的课程关联很容易联想到是拓扑排序,不过是方向相反,对于numCourses的判断,只要有节点出队的时候,让numCourses-1,最后判断numCourses是否为1即可

具体实现代码如下:

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        int[] indegrees=new int[numCourses];//作为入度表
        List<List<Integer>> adjacency=new ArrayList<>(); //邻接表
        Queue<Integer> queue=new LinkedList<>();
        for(int i=0;i<numCourses;i++){
            adjacency.add(new ArrayList<>());
        }
        //注意理解,如果从题目的角度来说应该是这样:
        // for(int[] c:prerequisites){
        //    indegrees[c[0]]++;     
        //    adjacency.get(c[1]).add(c[0]);
        // }
        // 因为正常来说【1,2】,是1指向2,所以我们要对2入度,但是这里题目的意思的要完成1,要先完成2.
        //不过我们这里还是采用正常的方向,因为对于判断有无环来说都是一样的,下面那个例题就不一样了
        for(int[] c:prerequisites){
            indegrees[c[1]]++; 
            adjacency.get(c[0]).add(c[1]);
        }
        for(int i=0;i<numCourses;i++){
            if(indegrees[i]==0){
                queue.add(i);
            }
        }
        while(!queue.isEmpty()){
            int num=queue.poll();
            numCourses--;
            for(int c:adjacency.get(num)){
                if(--indegrees[c]==0){
                    queue.add(c);
                }
            }
        }
        return numCourses>0?false:true;
    }
}

210. 课程表 II

这个题目就需要打印出拓扑排序了,其实只需要对上面的代码加一个数组即可,当然这样不是最好解法,只是为了套用上面的模板。

class Solution {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        int[] res=new int[numCourses];   //添加一个数组,记录出队的课程
        int[] indegrees=new int[numCourses];
        List<List<Integer>> adjacency=new ArrayList<>();
        Queue<Integer> queue=new LinkedList<>();
        int cur=0;
        for(int i=0;i<numCourses;i++){
            adjacency.add(new ArrayList<>());
        }
        
        //这里就必须按照方向来了,否则会输入想法的顺序
        for(int[] c:prerequisites){
            indegrees[c[0]]++;
            adjacency.get(c[1]).add(c[0]);
        }
        for(int i=0;i<numCourses;i++){
            if(indegrees[i]==0){
                queue.add(i);
            }
        }
        while(!queue.isEmpty()){
            int num=queue.poll();
            numCourses--;
            res[cur++]=num;
            for(int c:adjacency.get(num)){
                if(--indegrees[c]==0){
                    queue.add(c);
                }
            }
        }
        return numCourses==0?res:new int[0];
    }
}

关于拓扑排序基本上都可以参考上述的模板。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值