拓扑排序的java代码实现过程详解

news2024/11/14 23:28:36

拓扑排序

在现实生活中,我们经常会同一时间接到很多任务去完成,但是这些任务的完成是有先后次序的。以我们学习java学科为例,我们需要学习很多知识,但是这些知识在学习的过程中是需要按照先后次序来完成的。从java基础,到jsp/servlet,到ssm,到springboot等是个循序渐进且有依赖的过程。在学习jsp前要首先掌握java基础和html基础,学习ssm框架前要掌握jsp/servlet之类才行。
在这里插入图片描述
在这里插入图片描述

定义:
给定一副有向图,将所有的顶点排序,使得所有的有向边均从排在前面的元素指向排在后面的元素,此时就可以明
确的表示出每个顶点的优先级。下列是一副拓扑排序后的示意图:
在这里插入图片描述

1.检测有向图中的环

在这里插入图片描述

1.1 API设计

类名DirectedCycle
构造方法DirectedCycle(Digraph G):创建一个检测环对象,检测图G中是否有环
成员方法1.private void dfs(Digraph G,int v):基于深度优先搜索,检测图G中是否有环
2.public boolean hasCycle():判断图中是否有环
成员变量1.private boolean[] marked: 索引代表顶点,值表示当前顶点是否已经被搜索
2.private boolean hasCycle: 记录图中是否有环
3.private boolean[] onStack:索引代表顶点,使用栈的思想,记录当前顶点有没有已经处于正在搜索的有向路径上

在API中添加了onStack[] 布尔数组,索引为图的顶点,当我们深度搜索时:

  1. 在如果当前顶点正在搜索,则把对应的onStack数组中的值改为true,标识进栈;
  2. 如果当前顶点搜索完毕,则把对应的onStack数组中的值改为false,标识出栈;
  3. 如果即将要搜索某个顶点,但该顶点已经在栈中,则图中有环;

在这里插入图片描述
在这里插入图片描述

1.1 代码实现

public class DirectedCycle {
	//索引代表顶点,值表示当前顶点是否已经被搜索
	private boolean[] marked;
	//记录图中是否有环
	private boolean hasCycle;
	//索引代表顶点,使用栈的思想,记录当前顶点有没有已经处于正在搜索的有向路径上
	private boolean[] onStack;
	//创建一个检测环对象,检测图G中是否有环
	public DirectedCycle(Digraph G){
		//创建一个和图的顶点数一样大小的marked数组
		marked = new boolean[G.V()];
		//创建一个和图的顶点数一样大小的onStack数组
		onStack = new boolean[G.V()];
		//默认没有环
		this.hasCycle=false;
		//遍历搜索图中的每一个顶点
		for (int v = 0; v <G.V(); v++) {
			//如果当前顶点没有搜索过,则搜索
			if (!marked[v]){
			dfs(G,v);
			}
		}
	}
	//基于深度优先搜索,检测图G中是否有环
	private void dfs(Digraph G, int v){
		//把当前顶点标记为已搜索
		marked[v]=true;
		//让当前顶点进栈
		onStack[v]=true;
		//遍历v顶点的邻接表,得到每一个顶点w
		for (Integer w : G.adj(v)){
			//如果当前顶点w没有被搜索过,则递归搜索与w顶点相通的其他顶点
			if (!marked[w]){
				dfs(G,w);
			}
		//如果顶点w已经被搜索过,则查看顶点w是否在栈中,如果在,则证明图中有环,修改hasCycle标记,结束循环
			if (onStack[w]){
				hasCycle=true;
				return;
			}
		}
		//当前顶点已经搜索完毕,让当前顶点出栈
		onStack[v]=false;
	}
	//判断w顶点与s顶点是否相通
	public boolean hasCycle(){
		return hasCycle;
	}
}

2.基于深度优先的顶点排序

如果要把图中的顶点生成线性序列其实是一件非常简单的事,之前我们学习并使用了多次深度优先搜索,我们会发现其实深度优先搜索有一个特点,那就是在一个连通子图上,每个顶点只会被搜索一次,如果我们能在深度优先搜索的基础上,添加一行代码,只需要将搜索的顶点放入到线性序列的数据结构中,我们就能完成这件事。

2.1 顶点排序API设计

在这里插入图片描述

在API的设计中,我们添加了一个栈reversePost用来存储顶点,当我们深度搜索图时,每搜索完毕一个顶点,把该顶点放入到reversePost中,这样就可以实现顶点排序。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 代码实现过程

public class DepthFirstOrder {
	//索引代表顶点,值表示当前顶点是否已经被搜索
	private boolean[] marked;
	//使用栈,存储顶点序列
	private Stack<Integer> reversePost;
	//创建一个检测环对象,检测图G中是否有环
	public DepthFirstOrder(Digraph G){
		//创建一个和图的顶点数一样大小的marked数组
		marked = new boolean[G.V()];
		reversePost = new Stack<Integer>();
		//遍历搜索图中的每一个顶点
		for (int v = 0; v <G.V(); v++) {
			//如果当前顶点没有搜索过,则搜索
			if (!marked[v]){
				dfs(G,v);
			}
		}
	}
	//基于深度优先搜索,检测图G中是否有环
	private void dfs(Digraph G, int v){
		//把当前顶点标记为已搜索
		marked[v]=true;
		//遍历v顶点的邻接表,得到每一个顶点w
		for (Integer w : G.adj(v)){
		//如果当前顶点w没有被搜索过,则递归搜索与w顶点相通的其他顶点
			if (!marked[w]){
				dfs(G,w);
			}
		}
		//当前顶点已经搜索完毕,让当前顶点入栈
		reversePost.push(v);
	}
	//获取顶点线性序列
	public Stack<Integer> reversePost(){
		return reversePost;
	}
}

3.拓扑排序

前面已经实现了环的检测以及顶点排序,那么拓扑排序就很简单了,基于一幅图,先检测有没有环,如果没有环,
则调用顶点排序即可。

3.1 API设计

在这里插入图片描述

3.2 代码实现

public class TopoLogical {
	//顶点的拓扑排序
	private Stack<Integer> order;
	//构造拓扑排序对象
	public TopoLogical(Digraph G) {
		//创建检测环对象,检测图G中是否有环
		DirectedCycle dCycle = new DirectedCycle(G);
		if (!dCycle.hasCycle()){
		//如果没有环,创建顶点排序对象,进行顶点排序
			DepthFirstOrder depthFirstOrder = new DepthFirstOrder(G);
			order = depthFirstOrder.reversePost();
		}
	}
	//判断图G是否有环
	private boolean isCycle(){
		return order==null;
	}
	//获取拓扑排序的所有顶点
	public Stack<Integer> order(){
		return order;
	}
	
	public class DepthFirstOrder {
		//索引代表顶点,值表示当前顶点是否已经被搜索
		private boolean[] marked;
		//使用栈,存储顶点序列
		private Stack<Integer> reversePost;
		//创建一个检测环对象,检测图G中是否有环
		public DepthFirstOrder(Digraph G){
			//创建一个和图的顶点数一样大小的marked数组
			marked = new boolean[G.V()];
			reversePost = new Stack<Integer>();
			//遍历搜索图中的每一个顶点
			for (int v = 0; v <G.V(); v++) {
				//如果当前顶点没有搜索过,则搜索
				if (!marked[v]){
					dfs(G,v);
				}
			}
		}
		//基于深度优先搜索,检测图G中是否有环
		private void dfs(Digraph G, int v){
			//把当前顶点标记为已搜索
			marked[v]=true;
			//遍历v顶点的邻接表,得到每一个顶点w
			for (Integer w : G.adj(v)){
			//如果当前顶点w没有被搜索过,则递归搜索与w顶点相通的其他顶点
				if (!marked[w]){
					dfs(G,w);
				}
			}
			//当前顶点已经搜索完毕,让当前顶点入栈
			reversePost.push(v);
		}
		//获取顶点线性序列
		public Stack<Integer> reversePost(){
			return reversePost;
		}
	}
	public class DirectedCycle {
		//索引代表顶点,值表示当前顶点是否已经被搜索
		private boolean[] marked;
		//记录图中是否有环
		private boolean hasCycle;
		//索引代表顶点,使用栈的思想,记录当前顶点有没有已经处于正在搜索的有向路径上
		private boolean[] onStack;
		//创建一个检测环对象,检测图G中是否有环
		public DirectedCycle(Digraph G){
			//创建一个和图的顶点数一样大小的marked数组
			marked = new boolean[G.V()];
			//创建一个和图的顶点数一样大小的onStack数组
			onStack = new boolean[G.V()];
			//默认没有环
			this.hasCycle=false;
			//遍历搜索图中的每一个顶点
			for (int v = 0; v <G.V(); v++) {
				//如果当前顶点没有搜索过,则搜索
				if (!marked[v]){
				dfs(G,v);
				}
			}
		}
		//基于深度优先搜索,检测图G中是否有环
		private void dfs(Digraph G, int v){
			//把当前顶点标记为已搜索
			marked[v]=true;
			//让当前顶点进栈
			onStack[v]=true;
			//遍历v顶点的邻接表,得到每一个顶点w
			for (Integer w : G.adj(v)){
				//如果当前顶点w没有被搜索过,则递归搜索与w顶点相通的其他顶点
				if (!marked[w]){
					dfs(G,w);
				}
			//如果顶点w已经被搜索过,则查看顶点w是否在栈中,如果在,则证明图中有环,修改hasCycle标记,结束循环
				if (onStack[w]){
					hasCycle=true;
					return;
				}
			}
			//当前顶点已经搜索完毕,让当前顶点出栈
			onStack[v]=false;
		}
		//判断w顶点与s顶点是否相通
		public boolean hasCycle(){
			return hasCycle;
		}
	}

}

参考:黑马程序员Java数据结构与java算法

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

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

相关文章

中国电信携手鼎桥创新中心开展终端优选测评工作

近期&#xff0c;中国电信物联网开放实验室与鼎桥创新中心本着“优势互补、合作共赢、共同发展”的原则&#xff0c;携手联合开展了中国电信CTWing物联网市场终端优选测试&#xff0c;完成了多款行业智能终端的测评&#xff0c;为物联网市场上架产品的质量保驾护航&#xff0c;…

Node.js--》Express和路由模块的讲解使用

目录 Express Express的安装与使用 托管静态资源 nodemon Express路由 模块化路由 Express Express是基于Node.js平台&#xff0c;快速、开放、极简的Web开发框架。Express的作用和Node.js内置的http模块类似&#xff0c;是专门用来创建Web服务器的。Express的本质&…

cubeIDE开发, stm32独立看门狗IWDT的CubeMX配置及HAL库底层实现分析

一、STM32 的IWDT简介 2.1 看门狗原理 看门狗本质上就是一种计数器&#xff0c;和我们现实生活中一炷香现象、沙漏现象等是同理的&#xff0c;计数器一般有两种做法&#xff0c;一种是递增&#xff0c;超过固定阀值报警&#xff1b;一种是递减&#xff0c;通常值降到0时报警。后…

数据结构训练营5

开启蓝桥杯备战计划&#xff0c;每日练习算法一题&#xff01;&#xff01;坚持下去&#xff0c;想必下一年的蓝桥杯将会有你&#xff01;&#xff01;笔者是在力扣上面进行的刷题&#xff01;&#xff01;由于是第一次刷题&#xff01;找到的题目也不咋样&#xff01;所以&…

Databend in 2022

上一次写总结还是在回顾 Datafuse Labs 成立一周年&#xff0c;转眼来到 22 年末&#xff0c;Databend 也快要开始第三个年头的征程了。 今天就让我们一起回顾一下 Databend 在 2022 年的成果。 开源 Databend 是一款强大的云数仓&#xff0c;专为弹性和高效设计&#xff0c…

Spring Authorization Server 1.0 提供 Oauth 2.1 和 OpenID Connect 1.0 实现

1. 概述 在引入Java 社区两年半之后&#xff0c;VMWare发布了Spring Authorization Server 1.0。Spring 授权服务器项目构建在Spring Security之上&#xff0c;支持创建OpenID Connect 1.0身份提供者和OAuth 2.1授权服务器。该项目取代了不再维护的 Spring Security OAuth项目…

RHCEansible虚拟机初始化配置,ansible配置和安装

1.保证三台主机能互相通信&#xff0c;需要设置同一种网络模式&#xff08;nat&#xff09; 2.配置静态ip地址&#xff08;命令行&#xff0c;图形界面都可以&#xff09; server---192.168.171.100 node1---192.168.171.222 node2---192.168.171.10 3.更改主机名 永久更…

C++代码编程学习(1):简易通讯录的创建

2022年圣诞节到来啦&#xff0c;很高兴这次我们又能一起度过~ CSDN诚邀各位技术er分享关于圣诞节的各种技术创意&#xff0c;展现你与众不同的精彩&#xff01;参与本次投稿即可获得【话题达人】勋章【圣诞快乐】定制勋章&#xff08;1年1次&#xff0c;错过要等下一年喔&#…

消费市场的“跨年”:2023,数字新消费将引领市场何去何从?

配图来自Canva可画 2022&#xff0c;变局如同一个过滤器&#xff0c;每一个身处其中的消费者和消费品牌都在经受考验。我国人口红利在消退&#xff0c;竞争在加剧&#xff0c;需求在变化。光大证券研究所的数据显示&#xff0c;2022年来我国居民收入增速小幅改善&#xff0c;但…

Spring之Bean创建过程

1. 前言 Spring提供了xml、注解、JavaConfig多种方式来配置bean&#xff0c;不论何种方式&#xff0c;Spring最终都会将bean封装成BeanDefinition对象&#xff0c;Spring创建bean的依据也是通过BeanDefinition来完成的。 当我们调用getBean()方法获取bean实例时&#xff0c;不…

jmeter使用教程之登录接口(工作日记)

首先我们打开jmeter 快捷按钮&#xff1a;winr 会弹出快捷运行弹框&#xff0c;我们输入cmd 后点击回车 会弹出一个控制窗口&#xff0c;我们输入jmeter&#xff0c;然后回车 首次进入jmeter&#xff0c;页面显示空白页且默认英文 我们可以切换语言 【Options - Choose Lan…

AI前沿 | 利用训练好的模型库进行一键抠图(实例演示)

来源&#xff1a;投稿 作者&#xff1a;Struggling cyanobacteria 编辑&#xff1a;学姐 深度学习平台飞浆paddle的环境搭建 ① 效率更高的 gpu 版本的安装 通过 python -m pip install paddlepaddle-gpu -i https://mirror.baidu.com/pypi/simple来进行安装。 paddle.utils…

Dockerfile了解

目录 1.自定义centos&#xff0c;具备vim及ifconfig作用 2.自定义tomcat8 1.自定义centos&#xff0c;具备vim及ifconfig作用 cd /javaxl/software mkdir mydocker vi mycentosDockerfile 向 mycentosDockerfile 编辑内容 FROM centos:7 MAINTAINER zwc "zwcqq.com"…

解决Windows下使用cmd执行Python文件报错 ModuleNotFoundError: No module named ‘XXXX‘

一、问题产生 我在IDEA中可以正常执行的Python文件&#xff0c;想把它配置成每天固定时间执行的定时任务。我写了一个脚本在每天9点时执行Python文件&#xff0c;但是我在cmd中测试执行时遇到以下报错&#xff1a; Traceback (most recent call last):File "D:\dev\code…

AD5328手册翻译不完全(仅供参考)

最近要用到DAC生成数据波形&#xff0c;但是都是英文不好阅读&#xff0c;于是花费点时间翻译了大致数据内容并记录 一、特性 AD5308:16导联TSSOP中的8个缓冲8位DAC A版本&#xff1a;1 LSB INL&#xff0c;B版本&#xff1a;0.75 LSB INR AD5318:16导联TSSOP中的8个缓冲10…

互联网时代,VR全景营销的意义是什么?

互联网时代&#xff0c;很多事项我们都可以在手机上解决&#xff0c;随着互联网的不断发展&#xff0c;年轻人每天花在手机上的时间也在日益增加&#xff0c;这就将压力给到了线下实体店铺&#xff0c;年轻人不喜欢逛街&#xff0c;线下店铺的获客成本就会越来越高。同时也是由…

无人机测深三种方法-激光雷达,测深仪和探地雷达

最近搜素了论文和相关网页&#xff0c;博主总结了一下无人机测深总共有三种办法&#xff1a; &#xff08;1&#xff09;激光雷达&#xff1b; &#xff08;2&#xff09;测深仪&#xff1b; &#xff08;3&#xff09;探地雷达&#xff08;GPR&#xff09;。 1、激光雷达 …

如何在匿名上位机中显示自定义数据波形

匿名上位机相信很多人都用过&#xff0c;以前在调飞控的时候使用过&#xff0c;可以很直观的显示数据的波形&#xff0c;比如飞机姿态等。 最近在调试foc。很多数据在调试过程中&#xff0c;仅仅使用串口打印出来显示是很不直观的&#xff0c;比如正弦波&#xff0c;经典的马鞍…

Python冷知识-优雅的文档属性

Python是一门学习成本低但是使用场景广泛的语言&#xff0c;0基础2周左右就可以进行简单的脚本编写&#xff0c;但也正是因为这个原因&#xff0c;导致很多小伙伴的Python代码比较粗糙&#xff0c;那么我们来聊聊使用文档属性让Python代码更加的优雅。 设置文档属性 作为一名…

JUC并发编程学习笔记(二)Lock接口及线程间通信

2 Lock 接口 2.1 Synchronized 2.1.1 Synchronized 关键字回顾 synchronized 是 Java 中的关键字&#xff0c;是一种同步锁。它修饰的对象有以下几种&#xff1a; 修饰一个代码块&#xff0c;被修饰的代码块称为同步语句块&#xff0c;其作用的范围是大括号{}括起来的代码&…