图搜索算法 - 拓扑排序

相关文章:
数据结构–图的概念
图搜索算法 - 深度优先搜索法(DFS)
图搜索算法 - 广度优先搜索法(BFS)

拓扑排序

概念

几乎所有的工程都可分为若干个称作活动的子工程,而这些子工程之间,通常受着一定条件的约束,如其中某些子工程的开始必须在另一些子工程完成之后。对整个工程和系统,人们关心的是两个方面的问题:一是工程能否顺利进行;二是估算整个工程完成所必须的最短时间。这样两个问题都是可以通过对有向图进行拓扑排序和关键路径操作来解决的。当然这里说的工程,泛指一切的项目工程,如指令调度,数据序列化,软件安装包依赖关系,代码编译任务顺序等。

拓扑排序是对项目工程的排序,那么先来构建一个项目,比如这个项目制作番茄炒蛋,如图所示。
在这里插入图片描述
对一个有向无环图G进行拓扑排序,是将G中所有结点排成一个线性序列,使得图中任意一对结点u和v,u在线性序列中总是出现在v之前。如上面做菜顺序0-1-2-3-4-5-9-6-7-8,也可以0-3-2-1-4-5-9-6-7-8这样,都满足拓扑次序(Topological Order),也就是番茄总是要洗了再切,番茄要切成小块再炒,不能整个炒,这样的顺序不会改变,这简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

注意:偏序是指集合中仅有部分元素可比较大小(或先后),全序是指集合中所有元素可比较大小(或先后)。

原理

拓扑排序算法是基于深度优先搜索(以下简称DFS)的基础上做调整的,首先查看例子用DFS计算是怎样的结果,从结点【1】开始继续搜索,结果是0-1-4-7-8-2-5-9-3-6。显然这是不是拓扑排序的结果,因此要略为修改DFS。从一个结点出发,DFS是马上输出再递归进入相邻结点,这是不适合拓扑排序。这里应该先访问相邻的结点,若还有相邻结点,继续深入下一个结点,当所有相邻的结点都进入栈后,才把该结点推入栈,以下手动模拟此运算过程。

(1)首先初始化列表【visited】全部为【False】,所有结点刚开始都是未访问以及临时栈【stack】为空。然后从结点【0】开始,然后发现有3个结点,然后继续访问结点【1】,同理一直深入访问结点【4】、结点【7】和结点【8】,到这里没有发现相邻结点,那边我们把结点【8】入栈,然后回退到结点【7】,同样它也没有其他相邻结点,同样也入栈,同理结点【4】和结点【1】也一起入栈,如表所示。
在这里插入图片描述
(2)回到结点【0】,发现还有相邻结点【2】和【3】,然后我们访问结点【2】,同样一层层深入结点,直到结点【8】,由于它已经访问过了,所以不需要再次放到栈里面。然后回退到上一个结点【9】就可以放到栈里面,同理结点【5】和【2】也一起入栈,如表所示。
在这里插入图片描述
(3)继续访问未访问结点【3】,然后进入结点【6】,然后再想进一步访问结点【7】,发现它也在栈中,所以可以停止递归,把结点【6】推入栈,再把结点【3】入栈,这时候结点【0】所有相邻结点也访问完,也可以把它入栈,如表所示。
在这里插入图片描述
(4)这时候从栈中输出结果,从顶部结点开始结构为0-3-6-2-5-9-1-4-7-8,符合了拓扑排序的要求。
在编写代码前,先来分析算法的复杂度,如果图中有N个结点,E条边,在拓扑排序的过程中,因为复用【Graph】类,则使用邻接列表来表示图,所以查找所有结点的邻接结点所需时间为O(N),访问结点的邻接点所花时间为O(E),总的时间复杂度为O(N+E)。空间复杂度为递归深度,极限情况就是结点总数,则为O(N)。

class Graph(): """图类"""def __init__(self): self.graph = {}  # 初始化图的邻接列表def add_edge(self,u,v): if v:point = self.graph.get(u) # 尝试获取结点uif point:point.append(v)       # 若存在直接添加u-v的边else:self.graph[u] = [v]   # 若不存在,则先初始化u结点,然后再添加u-v的边else:self.graph[u] = list()  # 如果v没有值,添加一个空列表class GraphTopological(Graph):"""解决拓扑排序问题"""def topological_sort_util(self, v, visited, stack): visited[v] = True       # 该结点变为已访问for i in self.graph[v]: if visited[i] == False: # 结点未访问递归调用函数self.topological_sort_util(i, visited, stack) # 相邻结点都访问结束后,把该结点放到栈中stack.insert(0,v)  # 把新入栈元素放在表头def topological_sort(self):# 拓扑排序主程序visited = {}   # 初始化参数是否已经访问stack = [] # 初始化参数,用列表表示临时栈为空for key in self.graph.keys():visited[key] = False     # 值为未访问状态for node in self.graph.keys(): # 遍历所有结点 if visited[node] == False: # 结点是否已经访问self.topological_sort_util(node, visited, stack) # 递归进入结点print(stack) #把栈保存结果输出

创建【TopologicalGraph】类继承上面【Graph】类,复用构成邻接列表的过程。然后用列表构成栈,把递归结果保存在列表中,最后从栈表头开始输出结果便是拓扑排序的结果,现在用例子来测试结果是否符合预期。

g = GraphTopological() 
g.add_edge(0, 1) # 录入图的边
g.add_edge(0, 2) 
g.add_edge(0, 3) 
g.add_edge(1, 4) 
g.add_edge(2, 5) 
g.add_edge(3, 6)
g.add_edge(4, 7)
g.add_edge(5, 9)
g.add_edge(6, 7)
g.add_edge(7, 8)
g.add_edge(8, None)
g.add_edge(9, 8)
g.topological_sort() # 输出:[0, 3, 6, 2, 5, 9, 1, 4, 7, 8]

结果和刚才手动计算是一样,如果调换输入顺序,把第二行放到第四行,拓扑排序的结果如下。

[0, 1, 4, 3, 6, 7, 2, 5, 9, 8]

结果只是改变了遍历结点【1】,【2】和【3】的顺序,结果还是满足拓扑次序。

更多内容

想获取完整代码或更多相关图的算法内容,请查看我的书籍:《数据结构和算法基础Python语言实现》

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

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

相关文章

深入理解WPF的ResourceDictionary

深入理解WPF的ResourceDictionary 介绍 在WPF中,ResourceDictionary用于集中管理和共享资源(如样式、模板、颜色等),从而实现资源的重用和统一管理。本文详细介绍了ResourceDictionary的定义、使用和合并方法。 定义和用法 Res…

1057: 有向图的出度计算

解法&#xff1a; #include<iostream> using namespace std; int arr[100][100]; int main() {int vertex, edge;cin >> vertex >> edge;int i, j;while (edge--) {cin >> i >> j;arr[i][j] 1;}for (int i 0; i < vertex; i) {int sum 0;…

webjars学习

webjars介绍 官网&#xff1a;WebJars - Web Libraries in Jars github: WebJars GitHub 文档&#xff1a;WebJars - Documentation WebJAR 是一个用于管理Web前端依赖的工具。它允许开发者将特定的客户端库&#xff08;如JavaScript、CSS等&#xff09;打包成JAR&#xf…

python实现动态时钟功能

欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 一.前言 时钟,也被称为钟表,是一种用于测量、记录时间的仪器。时钟通常由时针、分针、秒针等计时仪器组成,是现代社会不可或缺的一种计时工具。它的发明和使用极大地改变了人类的生活方式和时间观念。 时钟的类型有很多,…

WordPress插件Show IDs by Echo,后台显示文章、页面、分类、标签、媒体库、评论、用户的ID

WordPress的这款Show IDs by Echo插件&#xff0c;可以让我们设置是增加一列ID还是直接在“编辑 |快速编辑 |查看”操作后面增加ID&#xff0c;而且支持展示以下内容的ID&#xff1a; 文章页面类别标签评论自定义帖子类型自定义分类法用户媒体 Show IDs by Echo插件的安装及启…

解决常见的Android问题

常见问题&#xff1a; 1、查杀&#xff1a; 查杀一般分为两个方向一种是内存不足的查杀&#xff0c;一种的是因为温度限频查杀&#xff0c;统称为内存查杀&#xff0c;两个问题的分析思路不同 1、内存不足查杀&#xff1a; 主要是因为当用户出现后台运行多个APP或者是相机等…

Verlog-串口发送-FPGA

Verlog-串口发送-FPGA 引言&#xff1a; ​ 随着电子技术的不断进步&#xff0c;串口通信已成为嵌入式系统和计算机外设中一种广泛使用的异步通信方式。串口通信因其简单性、可靠性以及对硬件资源的低要求&#xff0c;在数据传输领域扮演着重要角色。在FPGA&#xff08;现场可编…

AcwingWeb应用课学习笔记

y总Web课链接&#xff1a; VSCode自动格式化 选中Format On Save不起作用 在设置中搜索default formatter&#xff0c;修改成Prettier-Code formatter 标签 文本标签虽然很多&#xff0c;但大部分可看成是预定好样式的<div>和<span>。&#xff08;div也是由sp…

关于一致性,你该知道的事儿(下)

关于一致性&#xff0c;你该知道的事儿&#xff08;下&#xff09; 前言一、并发修改单个对象1.1 原子写操作1.2 显示加锁1.3 原子的TestAndSet1.4 版本号机制 二、 多个相关对象的一致性2.1 最大努力实现2.2 2PC && TCCC2.3.基于可靠消息的一致性方案2.4.Saga事务 三、…

ntfs文件系统的优势 NTFS文件系统的特性有哪些 ntfs和fat32有什么区别 苹果电脑怎么管理硬盘

对于数码科技宅在新购得磁盘之后&#xff0c;出于某种原因会在新的磁盘安装操作系统。在安装操作系统时&#xff0c;首先要对磁盘进行分区和格式化&#xff0c;而在此过程中&#xff0c;操作者们需要选择文件系统。文件系统也决定了之后操作的流程程度&#xff0c;一般文件系统…

基于opencv的车辆统计

车辆统计&#xff09; 一、项目背景二、整体流程三、常用滤波器的特点四、背景减除五、形态学开运算闭运算 六、项目完整代码七、参考资料 一、项目背景 检测并识别视频中来往车辆的数量 最终效果图&#xff1a; 二、整体流程 加载视频图像预处理&#xff08;去噪、背景减除…

picoCTF-Web Exploitation-Most Cookies

Description Alright, enough of using my own encryption. Flask session cookies should be plenty secure! server.py http://mercury.picoctf.net:53700/ Hints How secure is a flask cookie? 我们先下载server.py&#xff0c;分析逻辑 from flask import Flask, render…

【智能算法】鹭鹰优化算法(SBOA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2024年&#xff0c;Y Fu受到自然界中鹭鹰生存行为启发&#xff0c;提出了鹭鹰优化算法&#xff08;Secretary Bird Optimization Algorithm, SBOA&#xff09;。 2.算法原理 2.1算法思想…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-15.5讲 GPIO中断实验-通用中断驱动编写

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

C++:友元

友元&#xff08;friend&#xff09;是 C 中的一个关键字&#xff0c;用于建立类之间的友好关系&#xff1b;通过友元关系&#xff0c;一个类可以授权其他类或函数访问其私有成员或受保护成员&#xff0c;从而突破了 C 中的封装性&#xff1b;友元可以是类或函数&#xff0c;可…

css案例 tab上下滚动,左右滚动

效果图&#xff1a; 完整代码&#xff1a; <template><view class"content"><view class"content-item"><view class"content-title"><h4>美食热搜</h4><ul><li>火鸡面</li><li>糖…

Java---类和对象第一节

目录 1.面向对象初步认识 1.1什么是面向对象 1.2面向对象和面向过程的区别 2.类的定义和使用 2.1简单认识类 2.2类的定义格式 2.3类的实例化 2.4类和对象的说明 3.this关键字 3.1访问本类成员变量 3.2调用构造方法初始化成员变量 3.3this引用的特性 4.对象的构造以…

MES系统与WMS集成方法(满分100学习资料)

导语 大家好&#xff0c;我是智能仓储物流技术研习社的社长&#xff0c;老K。专注分享智能仓储物流技术、智能制造等内容。 新书《智能物流系统构成与技术实践》 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载 这份文件是关于MES系…

运用分支结构与循环结构写一个猜拳小游戏

下面我们运用平常所学的知识来写一个小游戏&#xff0c;这样能够加强我们学习的趣味性&#xff0c;并且能够更加的巩固我们所学的知识。 游戏代码&#xff1a; 直接放代码&#xff1a;&#xff08;手势可以使用数字来代替&#xff0c;比如0对应石头&#xff0c;1对应剪刀&…

Sass深度解析:性能优化的秘密

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…