拓扑排序-java

主要通过宽度优先搜索(BFS)来实现有向无环图的拓扑序列,邻接表存储图。数组模拟单链表、队列,实现BFS基本操作。

文章目录

前言

一、有向图的拓扑序列

二、算法思路 

 1.拓扑序列

2.算法思路

三、使用步骤

1.代码如下(示例):

2.读入数据:

3.代码运行结果

总结


前言

主要通过宽度优先搜索(BFS)来实现有向无环图的拓扑序列,邻接表存储图。数组模拟单链表、队列,实现BFS基本操作。


提示:以下是本篇文章正文内容,下面案例可供参考

一、有向图的拓扑序列

给定一个 n 个点 m 条边的有向图,点的编号是 1 到 n,图中可能存在重边和自环。

请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 −1。

若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x,y),x 在 A 中都出现在 y 之前,则称 A 是该图的一个拓扑序列。

输入格式

第一行包含两个整数 n 和 m。

接下来 m 行,每行包含两个整数 x 和 y,表示存在一条从点 x 到点 y 的有向边 (x,y)。

输出格式

共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。

否则输出 −1。

数据范围

1≤n,m≤100000

二、算法思路 

 1.拓扑序列

图1.1拓扑序列示例 

有向图的拓扑排序是指将有向无环图(DAG)中的所有顶点排成一个线性序列,使得对于图中的每一条有向边 (u, v),顶点 u 在序列中都出现在顶点 v 的前面。换句话说,如果图中存在一条从顶点 u 到顶点 v 的有向边,那么在拓扑排序中顶点 u 将在顶点 v 的前面。

在有向图中,每个顶点都有两种相关的度量:入度(in-degree)和出度(out-degree)。这些度量用于描述有向图中顶点之间的关系。

  • 入度:一个顶点的入度是指指向该顶点的边的数量。换句话说,对于顶点v,它的入度是有多少条边以v为终点。

  • 出度:一个顶点的出度是指从该顶点发出的边的数量。换句话说,对于顶点v,它的出度是有多少条边以v为起点。

各结点出入度示例
结点入度出度
102
211
320

一个有向无环图一定至少存在一个入度为0的点。 

开始入度为0的结点都是初始结点,然后当我们打印该结点,就将它指向的结点的入度擦去,然后我们在找入度为0的结点当作下一个结点重复上述操作,我们就可以得到该有向无环图的拓扑序列。

本次用宽度优先搜索来实现有向图的拓扑序列!

注:有向无环图才有拓扑序列,无向图是没有的。

2.算法思路

我们采用宽度优先搜索来实现上述操作。我们还是用邻接表法来存储图。我们还是用一维整型数组head,其中head[i]表示结点i相连的边,对应的边用单链表存储;还是用数组来模拟单链表,一维整型数组e用来存储结点的值,一维整型数组存储该结点指向的下一结点在e数组中的索引,整型变量index表示新创建的结点在e数组中的索引。

 添加a指向b边我们只需要在head数组中对应结点 a 的单链表中插入结点 b 即可。单链表的插入具体细节请看这篇博客单链表-java-CSDN博客。

    public static void add(int a, int b){e[index] = b;ne[index] = head[a];head[a] = index++;}

数组模拟单链表是基础!!! 

我们引入一个一维整型数组d,来存储图中每个点的入度;一维整型数组queue来模拟队列,整型变量hh时队头指针,整型变量rear时队尾指针。当这个点的入度为0时,我们就把它当作拓扑序列的起点,放入队列;当队列不为空时,我们弹出一个结点即t = queue[hh++];我们来遍历与结点 t相连的点,找到与结点 t 相连的点 j ,将结点 j 对应的入度减1 即 d[j]--;如果该结点的入度为0的话,就说明该结点没有上一个结点指向它,我们就让它入队。当队列为空时,如果我们的队尾指针等于n -1 的话就说明我们已经找出对应的拓扑序列。如果图中存在环的话,那么我们我们的队列为空的时候,队尾指针根本不可能到 n-1,一定比这个值小。

拓扑序列的本质就是我们每次把入度为0的结点打印出来,然后该结点指向的所有的结点的入度减1,然后再打印入度为0的结点。

所以拓扑排序就是对应队列数组从0到n - 1打印即可。

三、使用步骤

1.代码如下(示例):


import java.io.*;
import java.util.Arrays;public class Main {static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));static StreamTokenizer st = new StreamTokenizer(br);static int n,m;static int N = 100100;static int[] head = new int[N];static int[] e = new int[N];static int[] ne = new int[N];static int index;//存储每个点的入度static int[] d = new int[N];static int[] queue = new int[N];public static void main(String[] args) throws Exception{n = nextInt();m = nextInt();Arrays.fill(head,-1);while (m-- > 0){int a = nextInt();int b = nextInt();add(a,b);d[b]++;}if(topSort()){for(int i = 0;i < n;i++){pw.print(queue[i]+" ");}}else {pw.println("-1");}pw.flush();}public static boolean topSort(){int hh = 0;int rear = -1;//将起点放入队列for(int i = 1;i <= n;i++){if(d[i] == 0){queue[++rear] = i;}}while (hh <= rear){int t = queue[hh++];for(int i = head[t]; i != -1;i = ne[i]){//t指向jint j = e[i];d[j]--;if(d[j] == 0){queue[++rear] = j;}}}return rear == n - 1;}public static void add(int a, int b){e[index] = b;ne[index] = head[a];head[a] = index++;}public static int nextInt()throws Exception {st.nextToken();return (int)st.nval;}
}

2.读入数据:

3 3
1 2
2 3
1 3

3.代码运行结果

1 2 3 

总结

上述主要通过宽度优先搜索来实现有向无环图的拓扑序列,其中还是很常用的邻接表存储图。数组模拟单链表、队列,然后宽度优先搜索3部曲,大致就这些。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/25967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT 使用资源文件的注意点

不要存放没有使用的资源文件 即使在代码中没有使用到的资源文件&#xff0c;也会编译到执行文件或者DLL里面去这样会增大它的体积。如下 在代码没有使用这个资源文件(10.4M的2k图片)&#xff0c;但是编译出来的程序有 12M左右的大小 1 假设我们有一个比较复杂的项目&#…

ReentrantLock底层原理

ReentrantLock public ReentrantLock() {sync new NonfairSync(); }public ReentrantLock(boolean fair) {sync fair ? new FairSync() : new NonfairSync(); }ReentrantLock 的默认实现是非公平锁&#xff0c;实际上 ReentrantLock 中的方法&#xff0c;几乎都让 sync 实现…

springboot高校运动会信息管理系统设计与实现-计算机毕业设计源码92968

摘 要 本论文介绍了一个高校运动会信息管理系统的设计和实现过程。首先是高校运动会的需求分析和可行性分析&#xff0c;通过比较运动会的各个工作流程&#xff0c;确定了系统的数据流程和数据库结构&#xff0c;然后介绍了高校运动会信息管理系统开发所使用的软件开发工具&…

Java实现数据结构——顺序表

目录 一、前言 二、实现 2.1 增 2.2 删 2.3 查 2.4 改 2.5 销毁顺序表 三、Arraylist 3.1 构造方法 3.2 常用操作 3.3 ArrayList遍历 四、 ArrayList具体使用 4.1 杨辉三角 4.2 简单洗牌算法 一、前言 笔者在以前的文章中实现过顺序表 本文在理论上不会有太详细…

vscode侧边栏错乱重制

vscode 重制命令面板 View: Reset View Locations

三星系统因何而成?或许是因为吞噬了第四颗恒星

相比于其他的类似星体&#xff0c;这个特殊的三星系统拥有更大更紧密的星体。 三星 天文学家发现了前所未见的三星系统。相比于其他典型的三星系统&#xff0c;这一三星系统拥有更大的体积&#xff0c;并且排列也更加紧密&#xff0c;这也使得这一系统更加特别。科学家推测&am…

【题解】—— LeetCode一周小结23

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结22 3.分糖果 II 题目链接&#xff1a;1103. 分糖果 II 排排坐…

MySQL-数据处理(1)

029-数据处理函数之获取字符串长度 select length(我是Cupid); select char_length(我是Cupid);concat (concatenate) select concat(cu, pid, so, handsome);030-去除字符串前后空白-trim select trim( a b c );select trim(leading 0 from 000110); select t…

USB转I2C转SPI芯片CH341

CH340与CH341区别 CH340主要用于将USB转换为各种串口&#xff0c;CH340H和CH340S可以实现USB转并口。 CH341和340的不同之处在于CH341提供I2C和SPI接口&#xff0c;方便连接到I2C或SPI总线操作相关的器件。 CH341主要有6种封装。见表1. CH341T SSOP-20封装和丝印 USB 总线转接…

【服务实现读写分离】

文章目录 什么是读写分离基于Spring实现实现读写分离项目中常用的数据源切换依赖包 什么是读写分离 服务读写分离&#xff08;Service Read-Write Splitting&#xff09;是一种常见的数据库架构设计模式&#xff0c;旨在提高系统的性能和可扩展性。通过将读操作和写操作分离到…

分布式事务AP控制方案(上)

分布式事务控制方案 本篇文章给出一种要求高可用性&#xff08;AP思想&#xff09;的分布式事务控制方案 下篇新鲜出炉&#xff1a;点我查看 分布式事务控制方案1、业务背景2、本地消息表的设计3、对消息表的操作4、任务调度5、任务流程控制的抽象类6、课程发布的实现类7、总…

优质免费的 5 款翻译 API 接口推荐

当谈到翻译API时&#xff0c;我们通常指的是一种编程接口&#xff0c;它允许开发者将文本从一种语言翻译成另一种语言。这些API通常由专业的翻译服务提供商提供&#xff0c;如谷歌翻译 API、实时翻译API、腾讯翻译API、DeepL翻译API、Azure翻译API等。 这些API通常提供多种语言…

使用Redis的优势以及会引发的问题

优势 ①使用redis代表着高性能还有高并发&#xff0c;高性能很好理解&#xff0c;redis会缓存我们访问的数据。他是基于内存的&#xff0c;第一次访问数据库我们可能需要800ms&#xff0c;但是访问后如果使用redis进行缓存&#xff0c;第二次乃至后面访问相同的数据就只需要去…

使用opencv在图像上画带刻度线的对角线,以图像中心点为0点

使用OpenCV在图像上绘制带刻度线的对角线&#xff0c;可以通过以下步骤实现。我们将首先找到图像的中心点&#xff0c;然后绘制对角线线&#xff0c;并在这些线的适当位置绘制刻度线。以下是详细的C代码示例&#xff1a; void Draw_diagonal(cv::Mat& mat, double dFactor…

ViT:2 理解CLIP

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;则提…

《永生之后》读后

文章以2120年背景创作&#xff0c;人类进入永生之年&#xff0c;发现了延长寿命的药物。停滞的死亡&#xff0c;新生的继续造生了人口大爆炸&#xff0c;于是分成两个阵营-长生区&#xff08;不再繁衍后代&#xff09;与生死区&#xff08;不服用药物&#xff0c;仍然生老病死&…

PySpark教程(001):基础准备与数据输入

PySpark 学习目标 了解什么是Spark、PySpark了解为什么学习PySpark了解如何和大数据开发方向进行衔接 Spark是什么&#xff1f; Apache Spark是用于大规模数据处理的统一分析引擎。 简单来说&#xff0c;Spark是一款分布式的计算框架&#xff0c;用于调度成百上千的服务器…

MyBatis总结(2)- MyBatis实现原理(一)

Mybatis实现原理&#xff1a; 概括一句话&#xff1a;约定配置参数mybatis-config.xml&#xff0c;映射关系JavaBean-mapper.xml&#xff0c;用SqlSessionFactoryBuilder构建应用程序运行期间需要的SqlSessionFactory实例对象&#xff0c;当请求或方法需要执行CURD操作时&…

初识volatile

volatile&#xff1a;可见性、不能保证原子性(数据不安全)、禁止指令重排 可见性&#xff1a;多线程修改共享内存的变量的时候&#xff0c;修改后会通知其他线程修改后的值&#xff0c;此时其他线程可以读取到修改后变量的值。 指令重排&#xff1a;源代码的代码顺序与编译后字…

基于STM32开发的智能空气质量监控系统

⬇帮大家整理了单片机的资料 包括stm32的项目合集【源码开发文档】 点击下方蓝字即可领取&#xff0c;感谢支持&#xff01;⬇ 点击领取更多嵌入式详细资料 问题讨论&#xff0c;stm32的资料领取可以私信&#xff01; 目录 引言环境准备智能空气质量监控系统基础代码实现&…