算法系列--BFS解决拓扑排序

💕"请努力活下去"💕
作者:Lvzi
文章主要内容:算法系列–算法系列–BFS解决拓扑排序
在这里插入图片描述

大家好,今天为大家带来的是算法系列--BFS解决拓扑排序

前言:什么是拓扑排序
拓扑排序–解决有顺序的排序问题(要做事情的先后顺序)
在这里插入图片描述
几个基本概念

  1. 有向无环图:有方向,但是不存在环路
  2. 入度:有多少条路可以走到当前节点
  3. 出度:从当前节点出发,有多少条线路

拓扑排序问题的思路比较固定,难点在于灵活的采用不同的容器去建图和表示每个节点的入度信息,下面是拓扑排序问题的步骤:

Step1:建图

建立一个有向图来表示做事情的先后顺序

如何建图–灵活使用语言提供的容器

要存储的是:一个节点与其所相连的节点(边),两点构成一条线段
建立映射关系:
–哈希表存储
Map<Point,List< Point >>

表示每一个节点的入度:
我们是根据入度是否为0来决定先后顺序的

一个节点的入度就是有多少个指向该节点的边

使用数组int[] in表示

在这里插入图片描述

Step2.进行拓扑排序(队列 + bfs)

  1. 将所有入度为0的节点添加进队列
    在这里插入图片描述

  2. 循环队列

    • 获取头结点t,将t添加进入最后的结果之中(如果要表示的话)
    • 将与t相连的边删除–等价于将与t相连的点的入度减1
    • 判断与t相连的点的入度是否为0,如果为0,表示是新的起点,添加进队列之中
  3. 直到图中没有节点或者没有入度为0的节点(有环)
    在这里插入图片描述

注意有环的情况
在这里插入图片描述

一.课程表

题目链接:课程表
在这里插入图片描述

分析:

拓扑排序

  • 如果最后存在入度不为0的点–证明有环–无法按照p数组的顺序完成课程
  • 全为0,证明可以完成所有课程

代码:

class Solution {// 本题节点就是所有的可成
    public boolean canFinish(int n, int[][] p) {
        // 1.建图
        Map<Integer,List<Integer>> edges = new HashMap<>();
        int[] in = new int[n];

        for(int i = 0; i < p.length; i++) {
            int a = p[i][0], b = p[i][1];// b->a
            if(!edges.containsKey(b)) // 处理为空
                edges.put(b,new ArrayList<>());
            edges.get(b).add(a); // 建立关系
            in[a]++;// 入度加1
        }

        // 2.拓扑排序
        Queue<Integer> q = new LinkedList<>();
        for(int i = 0; i < n; i++)// 将所有入度为0的点添加进入队列
            if(in[i] == 0)
                q.add(i);

        // bfs
        // 得到对头元素 -- 删除与其相连的边 -- 找到下一个起始位置
        while(!q.isEmpty()) {
            int t = q.poll();
            for(int i : edges.getOrDefault(t,new ArrayList<>())) {// 将与t相连的点的入度减1
                in[i]--;
                if(in[i] == 0) q.add(i);// 如果入度为0,表示新的起点,添加进队列
            }
        }

        // 判断是否存在入度不为0 的点,如果存在,证明有环,则无法完成所有课程,返回false
        for(int i : in)
            if(i != 0) 
                return false;

        return true;
    }
}

总结:

  1. 注意本题p数组的指向,是b指向a
  2. 大致的过程很简单
    • 建图:建立点与点之间的联系(Map),统计所有点的入度情况–循环遍历即可
    • 拓扑排序:先将所有入度为0的点添加进入队列(起点),bfs循环遍历
  3. 一定要注意我们建的图可能有环,也可能无环,如果有环,最后图中一定有入度不为0的节点

二.课程表II

题目链接:课程表II
在这里插入图片描述

分析:

和上一道题目相同 只需记录排序结果即可

代码:

import java.util.Collections;
class Solution {
    public int[] findOrder(int n, int[][] p) {
        // 1.建图
        Map<Integer,List<Integer>> edges = new HashMap<>();
        int[] in = new int[n];

        for(int i = 0; i < p.length; i++) {
            int a = p[i][0], b = p[i][1];// b->a
            if(!edges.containsKey(b)) // 处理为空
                edges.put(b,new ArrayList<>());
            edges.get(b).add(a); 
            in[a]++;// 入度加1
        }

        // 2.拓扑排序
        Queue<Integer> q = new LinkedList<>();
        for(int i = 0; i < n; i++)// 将所有入度为0的点添加进入队列
            if(in[i] == 0)
                q.add(i);

        int[] ret = new int[n];
        int index = 0;
        // bfs
        while(!q.isEmpty()) {
            int t = q.poll();
            ret[index++] = t;
            for(int i : edges.getOrDefault(t,new ArrayList<>())) {// 将与t相连的点的入度减1
                in[i]--;
                if(in[i] == 0) q.add(i);// 如果入度为0,表示新的起点,添加进队列
            }
        }

        return index == n ? ret : new int[]{};
    }
}

三.⽕星词典

题目链接:⽕星词典
在这里插入图片描述

分析:

这里面的节点就是一个一个字符,题目最终要求的是字符的先后顺序–拓扑排序
三步:建图,拓扑排序,判断

在这里插入图片描述

代码:

class Solution {
    Map<Character,List<Character>> edges = new HashMap<>();// 建图使用
    Map<Character,Integer> in = new HashMap<>();// 统计每一个节点的入度信息

    public String alienOrder(String[] words) {
        // 初始化入度信息
        for(String str : words)
            for(int i = 0; i < str.length(); i++)
                in.put(str.charAt(i),0);

        // 建图  使用两层for循环来搜集信息
        int n = words.length;
        for(int i = 0; i < n - 1; i++) {
            for(int j = i + 1; j < n; j++) {
                String s1 = words[i], s2 = words[j];
                int len = Math.min(s1.length(),s2.length()), index = 0;
                while(index < len && s1.charAt(index) == s2.charAt(index))
                    index++;
				// 处理不合法的情况  s1 = abc  s2 = ab
                if(index == s2.length() && index < s1.length()) return "";
                // 走到两个字符串不相同的字母
                if(index >= len) continue;// 防止越界
                char prev = s1.charAt(index), behind = s2.charAt(index);
                if(!edges.containsKey(prev))
                    edges.put(prev,new ArrayList<>());
    
                if(!edges.get(prev).contains(behind)) {// 这里不加if判断也行,加了是为了减少冗余信息的加入
                    edges.get(prev).add(behind);
                    in.put(behind,in.get(behind) + 1);
                }
            }
        }

        // 2.拓扑排序
        StringBuffer ret = new StringBuffer();
        Queue<Character> q = new LinkedList<>();
        for(char ch : in.keySet()) // 将度为0的节点添加进队列之中
            if(in.get(ch) == 0) q.add(ch);

        while(!q.isEmpty()) {
            char t = q.poll();
            ret.append(t);
            // 遍历相连的点
            for(char ch : edges.getOrDefault(t,new ArrayList<>())) {
                in.put(ch,in.get(ch) - 1);
                if(in.get(ch) == 0) q.add(ch);
            }
        }

        // 判断是否存在入度不为0的点
        for(char ch : in.keySet()) 
            if(in.get(ch) != 0) return "";

        return ret.toString();
    }
}
  • 29
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DFS算法实现拓扑排序的代码如下所示: ```java package com.sh.zfc.graph.bfs; import org.junit.Test; import java.util.Arrays; import java.util.Stack; import static org.junit.Assert.*; public class TopSortTest { @Test public void dfs() { Digraph.GraphVertex\[\] vertices = new Digraph.GraphVertex\[4\]; vertices\[0\] = new Digraph.GraphVertex("A" , Arrays.asList(1,3)); vertices\[1\] = new Digraph.GraphVertex("B" , Arrays.asList(2,3)); vertices\[2\] = new Digraph.GraphVertex("C" ); vertices\[3\] = new Digraph.GraphVertex("D" ); Digraph<String> di = new Digraph<>(vertices); TopSort topsort = new TopSort(di); topsort.topSortByDFS(di); Stack<Integer> result = topsort.getReversePost(); Stack<Integer> expect = new Stack<>(); expect.push(2); expect.push(3); expect.push(1); expect.push(0); assertEquals(expect,result); } } ``` 这段代码使用了DFS算法来实现拓扑排序。首先创建了一个有向图,然后通过DFS算法进行拓扑排序。最后,将排序结果与预期结果进行比较,以验证算法的正确性。 #### 引用[.reference_title] - *1* [浅谈拓扑排序(基于dfs算法)](https://blog.csdn.net/langzitan123/article/details/79687736)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [算法之拓朴排序DFS实现](https://blog.csdn.net/tony820418/article/details/84588614)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [拓扑排序(topological sort)DFS](https://blog.csdn.net/Tczxw/article/details/47334785)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值