图搜索算法 - 拓扑排序

相关文章:
数据结构–图的概念
图搜索算法 - 深度优先搜索法(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.mzph.cn/bicheng/8115.shtml

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

相关文章

UART、TIMER

UART简介(通用异步收发器,通常称串口) UART,是一种串行、异步、全双工的通信协议,在嵌入式领域应用的非常广泛。 UART作为异步串行通信协议的一种,工作原理是将传输数据的每个二进制位一位接一位地传输。…

JavaScript:正则表达式属于字符串吗-不属于/字符串转正则表达式的两种方法

一、需求描述 js 字符串转正则表达式 二、理解正则表达式属于字符串吗? 正则表达式不属于字符串,它是一种用于匹配、查找和操作文本的模式。正则表达式是一种特殊的语法,用于描述字符串的特征。通过使用正则表达式,可以检查一个字符串是否…

SGP.22-V.3.1-安全2

有任何关于GSMA\IOT\eSIM\RSP\业务应用场景相关的问题,欢迎W: xiangcunge59 一起讨论, 共同进步 (加的时候请注明: 来自CSDN-iot). InitialiseSecureChannel 在 SGP.22 v3.1 技术规范的第 2.5.4.1 节 "Description of InitialiseSecureChannel Block"…

刷题之最爱的城市(卡码网,图论)

最爱的城市 #include<vector> #include<climits> #include<iostream> using namespace std; int path 0; void dfs(vector<vector<int>>& city, vector<bool>& visited, int city2, int startindex, int* result) {if (startinde…

[数据概念|方案实操][最新]数据资产入表4月速递

“ 在各地数据资产变现“热辣滚烫”” 国家数据局全国数据工作会议前后&#xff0c;数据资源“入表”的尝试在各地持续热火朝天地展开&#xff0c;多地实现数据资产入表和利用数据资产进行融资实现“零的突破”。 我们今天就把4月前后的案例做一个小结&#xff0c;之前的案例大…

linux / uboot一些编译调试命令

//声明环境变量 export PATH/home/fmsh/ft/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH export CROSS_COMPILEaarch64-linux-gnu- export ARCHarm64 export CCaarch64-linux-gnu-gcc //编译 make xxx_defconfig make menuconfig make -j8 //设置uboot启动参…

自然语言处理(NLP)技术及举例说明

自然语言处理&#xff08;NLP&#xff09;技术是一种人工智能技术&#xff0c;在处理人类自然语言的文本或语音时&#xff0c;可以帮助计算机理解、解释和生成语言。 以下是一些常见的自然语言处理技术的例子&#xff1a; 机器翻译&#xff1a;机器翻译技术可以将一种语言的文…

基于大数据+Hadoop的豆瓣电子图书推荐系统实现

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 系列文章目录 基于大数…

Pascal Content数据集

如果您想使用Pascal Context数据集&#xff0c;请安装Detail&#xff0c;然后运行以下命令将注释转换为正确的格式。 1.安装Detail 进入项目终端 #即 这是在我自己的项目下直接进行克隆操作&#xff1a; git clone https://github.com/zhanghang1989/detail-api.git $PASCAL…

美联储官员卡什卡利:判断通胀是否停滞为时尚早,利率可能维持较长时间

美联储明尼阿波利斯联邦储备银行行长尼尔卡什卡利近日表示&#xff0c;美联储需要更多数据才能判断通胀是否已经停滞不前&#xff0c;现在就断言通胀进展已经停滞还为时过早。卡什卡利的言论表明&#xff0c;美联储在通胀方面保持谨慎态度&#xff0c;同时强调利率政策可能维持…

连通“数据”,让制造变“聪明”

说起数据智能&#xff0c;你第一时间想到的是什么呢&#xff1f;是科技感十足的智慧城市&#xff1f;还是炫酷的人工智能景象&#xff1f; 数据作为企业的战略资产越来越受到重视&#xff0c;从最初的数据协助业务协同&#xff0c;转化为数据驱动业务&#xff0c;数据驱动运营…

review (fgetc/fputc)(fscanf/fprintf)(fgets)(fread/fwrite/fseek)

fgetc 统计行号 23 FILE* fpfopen("./1.c","r");24 if(fp0)25 {26 perror("错误原因");27 return -1;28 }29 int count0;30 while(1)31 {32 char retvalfgetc(fp);33 if(retvalEO…

命名空间、C++的输入输出、缺省参数(默认参数)、函数重载

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

Utreexod:支持Utreexo累加器的比特币全节点

1. 引言 前序博客&#xff1a; Utreexo&#xff1a;比特币UTXO merkle tree proof以节约节点存储空间Utreexo&#xff1a;优化Bitcoin UTXO集合的基于哈希的动态累加器Zerosync&#xff1a;构建基于STARK的Bitcoin证明系统 Utreexod为&#xff1a; 支持Utreexo累加器的比特…

【数据库原理及应用】期末复习汇总高校期末真题试卷06

试卷 一、选择题 1&#xff0e; ________是长期存储在计算机内的有组织,可共享的数据集合. A.数据库管理系统 B.数据库系统 C.数据库 D.文件组织 1&#xff0e; 有12个实体类型&#xff0c;并且它们之间存在15个不同的二元联系&#xff0c;其中4个是1:1联系类型&#xff0c;5…

如何恢复回收站中被删除的文件?3个恢复策略,实测有用!

“刚刚一不小心把回收站清空了&#xff0c;大家有什么好用的方法可以帮我恢复回收站中删除的文件吗&#xff1f;快帮帮我吧&#xff01;” 在使用电脑的过程中&#xff0c;我们有时可能会不小心将重要的文件或文件夹删除到回收站&#xff0c;并且随后可能进一步从回收站中彻底删…

羊大师分析,为什么羊奶是孩子的理想饮品?

羊大师分析&#xff0c;为什么羊奶是孩子的理想饮品&#xff1f; 羊奶&#xff0c;作为一种传统的营养饮品&#xff0c;近年来逐渐受到家长们的青睐&#xff0c;成为孩子们的理想饮品。那么&#xff0c;羊大师将为大家讲解&#xff0c;为什么羊奶能够赢得如此多的赞誉&#xf…

Redis 源码安装(CentOS 单机)

序言 本文给大家介绍如何在 CentOS 上&#xff0c;通过 Redis 源码单机部署 Redis 服务。 一、部署流程 通过官网下载源码 # 下载源码 wget https://download.redis.io/redis-stable.tar.gz# 解压源码包 tar -xzvf redis-stable.tar.gz在 linux 中执行以下命令&#xff0c;安…

Unity3D DOTween

简单介绍一下 DOTween 插件的使用。 导入插件 先到 Asset Store 获取 DOTween 插件&#xff0c;然后在 Package Manager 的 My Assets 中搜索&#xff0c;下载并导入插件。 导入后&#xff0c;会自动弹出一个窗口&#xff0c;提示需要先对插件进行配置。 点击上图中的按钮&am…

IDEA 插件,提高开发效率

AI 编程助手&#xff1a; 通义灵码: 搜索 tongyi 安装 fitten code: 搜索 fitten code 安装 其他&#xff1a; Alibaba Java Coding Guidelines&#xff1a;阿里巴巴代码规范 Mybatis log free&#xff1a;mybatis 日志助手能拼接带参数的完整sql Save Actions &#xff1a;代…