拓扑排序
dfs实现拓扑排序原理

拓扑排序拓扑排序是一种对有向无环图(DAG)进行排序的算法,它可以将图中的节点按照一定的顺序进行排列。
拓扑排序算法常用于任务调度、依赖关系分析等领域。
拓扑排序的基本原理是通过深度优先搜索(DFS)来遍历图中的节点,并根据节点的访问顺序进行排序。
在DFS过程中,首先从某个节点出发,沿着一条路径一直访问下去,直到无法继续访问为止。
然后回溯到上一个节点,继续访问未被访问过的邻接节点。
这样不断地递归下去,直到所有节点都被访问过为止。
拓扑排序算法的基本步骤如下:1.创建一个空的结果列表,用于存储排序后的节点。
2.选择一个未被访问过的节点作为起始节点。
3.从起始节点开始进行DFS遍历,将访问到的节点标记为已访问。
4.在DFS遍历过程中,如果遇到某个节点的所有邻接节点都已经被访问过,则将该节点加入结果列表。
5.继续选择下一个未被访问过的节点作为起始节点,重复步骤3和步骤4,直到所有节点都被访问过。
6.返回结果列表,即为拓扑排序的结果。
下面通过一个具体的例子来说明拓扑排序的原理。
假设有如下的有向无环图(DAG):A ->B -> C| |v vD -> E首先选择一个未被访问过的节点作为起始节点,假设选择节点A。
从节点A开始进行DFS遍历,首先访问节点A,并将其标记为已访问。
接下来访问节点A的邻接节点B,然后继续访问节点B的邻接节点C。
由于节点C没有邻接节点,所以将节点C加入结果列表,并回溯到节点B。
接着访问节点B的另一个邻接节点E,将节点E 加入结果列表。
然后回溯到节点A,继续访问节点A的另一个邻接节点D,将节点D加入结果列表。
最后回溯到节点A,节点A的所有邻接节点都已经被访问过,将节点A加入结果列表。
此时,结果列表中的节点顺序为C、E、D、A。
但是根据拓扑排序的定义,结果列表应该是一个满足所有依赖关系的顺序。
在这个例子中,节点B依赖于节点A,所以节点B应该在节点A之后。
为了达到这个目的,可以将结果列表中的节点顺序反转,得到最终的拓扑排序结果为A、D、E、C、B。
拓扑排序例子 -回复

拓扑排序例子-回复什么是拓扑排序?为什么要进行拓扑排序?如何进行拓扑排序?这篇文章将为你逐步解答这些问题。
拓扑排序是一种用于有向无环图(DAG)的算法,它将图中的节点按照一种特定的顺序进行排序。
拓扑排序往往用于解决有依赖关系的任务调度问题,其中任务的执行必须按照一定的顺序。
通过拓扑排序,我们可以确定任务的执行顺序,确保每个任务在它所依赖的任务执行完毕之后再执行。
那么为什么要进行拓扑排序呢?想象一下,你要为一本书编写目录,你希望按照章节的顺序来编写目录,否则读者可能会迷失在无序的章节中。
在这个例子中,每个章节都相当于一个任务,它们之间存在一定的依赖关系,因为后续的章节可能会引用之前的内容。
通过拓扑排序,你可以确定每个章节的先后顺序,确保目录的编写顺利进行。
那么如何进行拓扑排序呢?拓扑排序使用了一种叫做“深度优先搜索”的算法。
算法从一个未访问的节点开始遍历图,当遍历到一个节点时,它将其标记为已访问,并继续遍历该节点的所有邻接节点。
当一个节点的所有邻接节点都被访问完毕后,它将被添加到排序结果的头部。
最终,我们得到的排序结果就是拓扑排序的结果。
下面,我们来举一个具体的例子来演示拓扑排序的过程。
假设我们有以下的任务依赖关系图:[1] > [2] > [4]\\ v> [3] > [5]在这个图中,节点表示任务,箭头表示任务之间的依赖关系。
例如,节点2依赖于节点1,节点4依赖于节点2,等等。
我们的目标是按照依赖关系的顺序对节点进行排序。
首先,我们从一个未访问的节点开始,假设我们选择节点1。
我们接下来需要遍历节点1的所有邻接节点,即节点2和节点3。
然后,我们继续遍历这两个节点的邻接节点,依次为节点4和节点5。
由于节点4和节点5都没有邻接节点,它们被添加到排序结果的头部。
接着,我们回溯到节点2,它的邻接节点3已经被访问过了,所以它也被添加到排序结果的头部。
最后,我们回溯到节点1,将其添加到排序结果的头部。
什么是拓扑排序?

什么是拓扑排序?
拓扑排序是一种对有向无环图(DAG)进行排序的算法,它可以将图中的顶点
按照一定的顺序排列,使得图中任意一条边的起点在排列中都出现在终点之前。
具体来说,拓扑排序的过程是这样的:
1. 首先,找到图中入度为0的顶点(即没有任何边指向它的顶点),将其加入到排序的结果中。
2. 然后,移除这个顶点以及由它出发的所有边,更新剩余顶点的入度。
3. 重复以上步骤,直到所有的顶点都被加入到排序结果中或者发现图中存在环。
如果最终所有的顶点都被加入到排序结果中,那么这个排序就是图的一个拓扑
排序;如果在过程中发现了环,那么图不具有拓扑排序。
拓扑排序的应用非常广泛,比如在软件工程中可以用来解决模块的依赖关系,
或者在任务调度中确定任务的执行顺序等等。
这个算法的时间复杂度为O(V+E),其中V为顶点的数量,E为边的数量。
图基本算法拓扑排序(基于dfs)

图基本算法拓扑排序(基于dfs) 拓扑排序,是对有向⽆回路图进⾏排序,以期找到⼀个线性序列,这个线性序列在⽣活正可以表⽰某些事情完成的相应顺序。
如果说所求的图有回路的话,则不可能找到这个序列。
在⼤学数据结构课上,我们知道求拓扑排序的⼀种⽅法。
⾸先⽤⼀个⼊度数组保存每个顶点的⼊度。
在进⾏拓扑排序时,我们需要找到⼊度为0的点,将其存⼊线性序列中,再将其从图中删除(与它相关的边都删除,相邻的顶点的⼊度均减1),再重复上⾯的操作,直⾄所有的顶点都被找到为⽌。
如果不对每次找⼊度为0的顶点的⽅法进⾏处理,⽽直接去遍历⼊度数组,则该算法的时间复杂度为O(|V|2),如果使⽤⼀个队列来保存⼊度为0的顶点,则可以将这个算法的复杂度降为O(V+E)。
今天在算法导论上看了⽤dfs来求拓扑排序的算法,才发现其⾼深之处,膜拜之Orz…下⾯是算法导论的叙述: 本节说明了如何运⽤深度优先搜索,对⼀个有向⽆回路图(dag)进⾏拓扑排序。
对有向⽆回路图G=(V,E)进⾏拓扑排序后,结果为该图顶点的⼀个线性序列,满⾜如果G包含边(u, v),则在该序列中,u就出现在v的前⾯(如果图是有回路的,就不可能存在这样的线性序列)。
⼀个图的拓扑排序可以看成是图中所有顶点沿⽔平线排列⽽成的⼀个序列。
使得所有的有向边均从左指向右。
因此,拓扑排序不同于通常意义上的排序。
在很多应⽤中,有向⽆回路图⽤于说明时间发⽣的先后次序,下图1即给出⼀个实例,说明Bumstead教授早晨穿⾐的过程。
他必须先穿好某些⾐服,才能再穿其他⾐服(如先穿袜⼦后穿鞋),其他⼀些⾐服则可以按任意次序穿戴(如袜⼦和裤⼦),在图1中,有向边<u,v>表⽰⾐服u必须先于⾐服v穿戴。
因此,该图的拓扑排序给出了⼀个穿⾐的顺序。
图2说明了对该图进⾏拓扑排序后,将沿⽔平线⽅向形成⼀个顶点序列,使得图中所有有向边均从左指向右。
拓扑排序算法具体步骤如下:1、调⽤dfs_travel();2、在dfs_travel()每次调⽤dfs()的过程中,都记录了顶点s的完成时间,将顶点s按完成顺序保存在存放拓扑排序顺序的数组topoSort[]中。
拓扑排序应用场景

拓扑排序应用场景拓扑排序是一种常用的图算法,用于解决一些特定的应用场景。
它的主要作用是对有向无环图(DAG)中的节点进行排序,使得所有的边从前向后指向排列的顺序。
在实际应用中,拓扑排序被广泛应用于任务调度、依赖关系分析、编译优化等领域。
在任务调度中,拓扑排序可以用来确定任务的执行顺序。
假设有一组任务,每个任务都有一些依赖关系,即某些任务必须在其他任务执行之后才能开始。
这时候,我们可以将任务看作图中的节点,依赖关系看作图中的边,利用拓扑排序算法确定任务的执行顺序。
通过拓扑排序,我们可以确保没有任务在其依赖任务执行之前开始,从而保证任务的正确执行。
拓扑排序也可以应用于依赖关系分析。
在软件开发中,各个模块之间可能存在依赖关系,即某些模块需要依赖其他模块的输出结果才能正常工作。
通过使用拓扑排序,可以分析模块之间的依赖关系,找出模块之间的依赖顺序,从而保证软件的正确运行。
另一个应用场景是编译优化。
在编译过程中,源代码会经过多个阶段的处理,例如词法分析、语法分析、语义分析等。
这些处理过程之间也存在依赖关系,必须按照一定的顺序进行。
通过拓扑排序,可以确定编译过程中各个阶段的执行顺序,从而提高编译的效率和准确性。
除了上述应用场景,拓扑排序还可以用于解决其他问题。
例如,可以用拓扑排序来判断一个有向图是否存在环路,如果拓扑排序中存在环路,则图中存在环路;反之,如果拓扑排序中不存在环路,则图中不存在环路。
此外,拓扑排序还可以用于确定关键路径,即在一组任务中找出耗时最长的路径,从而可以优化任务的执行时间。
拓扑排序是一种非常实用的图算法,广泛应用于任务调度、依赖关系分析、编译优化等领域。
通过拓扑排序,可以确定任务的执行顺序,分析模块之间的依赖关系,优化编译过程,判断图中是否存在环路,确定关键路径等。
这些应用场景都可以通过拓扑排序来解决,从而提高工作效率和准确性。
详解C++实现拓扑排序算法

详解C++实现拓扑排序算法⽬录⼀、拓扑排序的介绍⼆、拓扑排序的实现步骤三、拓扑排序⽰例⼿动实现四、拓扑排序的代码实现五、完整的代码和输出展⽰⼀、拓扑排序的介绍拓扑排序对应施⼯的流程图具有特别重要的作⽤,它可以决定哪些⼦⼯程必须要先执⾏,哪些⼦⼯程要在某些⼯程执⾏后才可以执⾏。
为了形象地反映出整个⼯程中各个⼦⼯程(活动)之间的先后关系,可⽤⼀个有向图来表⽰,图中的顶点代表活动(⼦⼯程),图中的有向边代表活动的先后关系,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能进⾏。
通常,我们把这种顶点表⽰活动、边表⽰活动间先后关系的有向图称做顶点活动⽹(Activity On Vertex network),简称AOV⽹。
⼀个AOV⽹应该是⼀个有向⽆环图,即不应该带有回路,因为若带有回路,则回路上的所有活动都⽆法进⾏(对于数据流来说就是死循环)。
在AOV⽹中,若不存在回路,则所有活动可排列成⼀个线性序列,使得每个活动的所有前驱活动都排在该活动的前⾯,我们把此序列叫做拓扑序列(Topological order),由AOV⽹构造拓扑序列的过程叫做拓扑排序(Topological sort)。
AOV⽹的拓扑序列不是唯⼀的,满⾜上述定义的任⼀线性序列都称作它的拓扑序列。
⼆、拓扑排序的实现步骤1.在有向图中选⼀个没有前驱的顶点并且输出2.从图中删除该顶点和所有以它为尾的弧(⽩话就是:删除所有和它有关的边)3.重复上述两步,直⾄所有顶点输出,或者当前图中不存在⽆前驱的顶点为⽌,后者代表我们的有向图是有环的,因此,也可以通过拓扑排序来判断⼀个图是否有环。
三、拓扑排序⽰例⼿动实现如果我们有如下的⼀个有向⽆环图,我们需要对这个图的顶点进⾏拓扑排序,过程如下:⾸先,我们发现V6和v1是没有前驱的,所以我们就随机选去⼀个输出,我们先输出V6,删除和V6有关的边,得到如下图结果:然后,我们继续寻找没有前驱的顶点,发现V1没有前驱,所以输出V1,删除和V1有关的边,得到下图的结果:然后,我们⼜发现V4和V3都是没有前驱的,那么我们就随机选取⼀个顶点输出(具体看你实现的算法和图存储结构),我们输出V4,得到如下图结果:然后,我们输出没有前驱的顶点V3,得到如下结果:然后,我们分别输出V5和V2,最后全部顶点输出完成,该图的⼀个拓扑序列为:v6–>v1—->v4—>v3—>v5—>v2四、拓扑排序的代码实现下⾯,我们将⽤两种⽅法来实现我么的拓扑排序:1.Kahn算法2.基于DFS的拓扑排序算法⾸先我们先介绍第⼀个算法的思路:Kahn的算法的思路其实就是我们之前那个⼿动展⽰的拓扑排序的实现,我们先使⽤⼀个栈保存⼊度为0 的顶点,然后输出栈顶元素并且将和栈顶元素有关的边删除,减少和栈顶元素有关的顶点的⼊度数量并且把⼊度减少到0的顶点也⼊栈。
拓扑排序及关键路径

2.有向图在实际问题中的应用 一个有向图可以表示一个施工流程图,或产品生产流程
图,或数据流图等。设图中每一条有向边表示两个子工程之 间的先后次序关系。
若以有向图中的顶点来表示活动,以有向边来表示活动 之间的先后次序关系,则这样的有向图称为顶点表示活动的 网 (Activity On Vertex Network),简称AOV网。
这样,每个活动允许的时间余量就是l(i) - e(i)。而关键活动 就是l(i) - e(i) = 0的那些活动,即可能的最早开始时间e(i)等于 允许的最晚开始时间l(i)的那些活动就是关键活动。
4.寻找关键活动的算法 求AOE网中关键活动的算法步骤为: (1)建立包含n+1个顶点、e条有向边的AOE网。其中,顶
(4)从汇点vn开始,令汇点vn的最晚发生时间vl[n]=ve[n], 按逆拓扑序列求其余各顶点k(k=n-1,n-2,…,2,1,0)的最晚发生 时间vl[k];
(5)计算每个活动的最早开始时间e[k] (k=1,2,3,…,e); (6)计算每个活动的最晚开始时间l[k] (k=1,2,3,…,e); (7)找出所有e[k]= l[k]的活动k,这些活动即为AOE网的 关键活动。
上述算法仅能得到有向图的一个拓扑序列。改进上述 算法,可以得到有向图的所有拓扑序列。
如果一个有向图存在一个拓扑序列,通常表示该有向 图对应的某个施工流程图的一种施工方案切实可行;而 如果一个有向图不存在一个拓扑序列,则说明该有向图 对应的某个施工流程图存在设计问题,不存在切实可行 的任何一种施工方案。
事件可能的最早开始时间υe(k):对于顶点υk代表的事件, υe(k)是从源点到该顶点的最大路径长度。在一个有n+1个事 件的AOE网中, 源点υ0的最早开始时间υe(0)等于0。事件υk (k=1,2,3,…,n)可能的最早开始时间υe(k)可用递推公式表 示为:
拓扑排序求最长路径

拓扑排序求最长路径1. 什么是拓扑排序?拓扑排序是对有向无环图(DAG)进行排序的一种算法。
在有向图中,如果存在一条从节点A到节点B的有向边,那么节点A就必须在节点B之前进行排序。
拓扑排序通过将图中的节点按照一定的顺序进行排列,使得任意两个节点之间不存在环。
拓扑排序可以应用于许多问题,比如任务调度、依赖关系分析等。
2. 拓扑排序算法2.1. 算法原理拓扑排序算法基于深度优先搜索(DFS)或广度优先搜索(BFS)实现。
其基本思想是通过遍历图中的所有节点,并记录每个节点的入度(即指向该节点的边数)。
然后从入度为0的节点开始遍历,并将其加入结果列表中。
然后将与该节点相邻的节点的入度减1,并将新入度为0的节点加入结果列表。
重复此过程直到所有节点都被加入结果列表。
2.2. 算法步骤以下是拓扑排序算法的详细步骤:1.初始化一个空结果列表result和一个空队列queue。
2.遍历图中所有节点,并统计每个节点的入度。
3.将入度为0的节点加入队列queue。
4.当队列queue不为空时,执行以下步骤:–从队列queue中取出一个节点node,并将其加入结果列表result。
–遍历与节点node相邻的所有节点,并将它们的入度减1。
–如果某个节点的入度减为0,则将其加入队列queue。
5.如果结果列表result的长度等于图中的节点数,则说明拓扑排序成功;否则,说明图中存在环。
以下是使用Python语言实现拓扑排序算法的示例代码:from collections import defaultdict, dequedef topological_sort(graph):# 统计每个节点的入度in_degree = defaultdict(int)for node in graph:for neighbor in graph[node]:in_degree[neighbor] += 1# 初始化结果列表和队列result = []queue = deque()# 将入度为0的节点加入队列for node in graph:if in_degree[node] == 0:queue.append(node)# 拓扑排序while queue:node = queue.popleft()result.append(node)for neighbor in graph[node]:in_degree[neighbor] -= 1if in_degree[neighbor] == 0:queue.append(neighbor)if len(result) == len(graph):return resultelse:return None3. 拓扑排序求最长路径在有向无环图中,求最长路径可以通过拓扑排序算法来实现。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
拓扑排序摘要拓扑排序是求解网络问题所需的主要算法。
管理技术如计划评审技术和关键路径法都应用这一算法。
通常,软件开发、施工过程、生产流程、程序流程等都可作为一个工程。
一个工程可分成若干子工程,子工程常称为活动。
活动的执行常常伴随着某些先决条件,一些活动必须先于另一活动被完成。
利用有向图可以把这种领先关系清楚地表示出来。
而有向图的存储可以用邻接表和逆邻接表做存储结构来实现。
最后用拓扑排序表示出来就可以了。
拓扑排序有两种,一种是无前趋的顶点优先算法,一种是无后继的顶点优先算法,后一种的排序也就是逆拓扑排序。
关键词:拓扑排序;逆拓扑排序;有向图;邻接表;逆邻接表THE OPERATOR ORDERING PROBLEM IN QUANTUMHAMITONIAN FOR SOME CONSTRAINT SYSTEMSABSTRACTTopological sort is the main method to solve network problems. Management techniques such as PERT and critical path method is the application of this algorithm. Typically, software development, the construction process, production processes, procedures, processes, etc. can be used as a project. A project can be divided into several sub-projects, often referred to as sub-project activities. The implementation of activities often associated with certain preconditions, some of the activities must be completed before another activity. Use has lead to the relationship of this figure can be expressed clearly. While storage can be used to map the inverse adjacency list and adjacency table to do storage structures. Finally, topological sort that out on it. Topological sort, there are two, one is the predecessor of the vertex without first algorithm, a successor of the vertex is no priority algorithm, the latter sort is the inverse topological sort.Key words:topological sort; inverse topological; have to figure; adjlink; inverse adjlink目录1需求分析 (1)1.1设计内容 (1)1.2设计要求 (1)2概要设计 (1)2.1邻接表 (1)2.2逆邻接表 (2)2.3有向图的拓扑排序........................................................................... (3)2.4有向图的逆拓扑排序.............. ........ (4)3详细设计 (4)3.1 有向图拓扑排序和逆拓扑排序 (4)3.1 .1 邻接表存储 (4)3.1.2 逆邻接表存储 (9)4 调试分析 (11)4.1 回顾讨论和分析 (11)4.2 算法复杂度的分析 (11)4.3 经验和体会 (12)5用户使用说明 (12)6 测试数据和测试结果 (12)参考文献 (15)附录 (16)1 需求分析1.1设计内容编写函数实现有向图的拓扑排序以及逆拓扑排序,要求有向图用邻接表和逆邻接表作为存储结构分别实现,并比较两者算法时间复杂度。
1.2 设计要求1.将有向图分别用邻接表与逆邻接表存储2.实现有向图的拓扑排序和逆拓扑排序3.比较两种排序的时间复杂度2 概要设计图是一种非常有用的数据结构。
因为图的结构复杂而使用广泛,所以其存储表示方法也是多种多样,对应于不用的应用问题有不用的表示方法。
2.1 邻接表邻接表是图的一种链式存储结构。
用邻接表法表示图需要保存一个顺序存储的结点表和n个链接存储的边表。
结点表的每个表目对应于一个结点,每个表目包括两个字段:一个是结点的数据或指向结点数据的指针,另一个是指向此结点的边表的指针。
图的每个结点都有一个边表,一个结点的边表的每个表目对应于与该结点相关联的一条边,每个表目包括两个字段:一个是与此边相关联的另一个结点的序号,另一个是指向边表的下一个表目的指针。
用邻接表法表示有向图,根据需要可以保存每个结点的出边表(即以该结点为始点的边的表),也可以保存每个结点的入边表(即以该结点为终点的边的表)。
只保存入边表和出边表之一,则存储n个结点m条边的有向图需要n+m个单元。
在这种存储方法中,对于图中的每一个顶点分别建立一个线性链表。
每个链表前面设置一个头结点,称之为顶点结点。
每个顶点结点由两个域组成,如图1-1:图1-1 邻接表的顶点结点构造邻接表的第i个链表中的每一个链结点称之为边界点,它表示依附于第i个顶点的一条边,其链结点构造为图1-2 邻接表的边结点构造一个图的邻接表存储结构可形式地说明如下://------图的邻接表存储表示-----------------#define MAX_VERTEX_NUM 20typedef struct ArcNode{int adjvex; //该弧所指向的顶点的位置struct ArcNode *nextarc; // 指向下一条弧的指针InfoType *info; //该弧相关信息的指针}ArcNode;typeder struct VNode{V ertexType data; //顶点信息ArcNode *firstarc; //指向第一条依附该顶点的弧的指针}VNode,AdjList[MAX_VERTEX_NUM];typeder struct{AdjList vertices;int vexnum,arcnum; //图的当前顶点数和弧数int kind; //图的种类标志}ALGraph;2.2 逆邻接表图的逆邻接表反应的是结点的入度邻接情况。
也就是说,按照建立邻接表的基本思想,对于有向图中每一个顶点,建立以该顶点为终点(弧头)的一个链表,即把所有以该顶点为终止顶点的边结点链接为一个线性链表。
在有向图中,为图中每个顶点vi建立一个入边表的方法称为逆邻接表的表示法。
入边表中的每个表结点均对应一条以vi为终点(即射入vi)的边。
2.3有向图的拓扑排序拓扑排序是有向图的一种重要运算。
给出有向图G=(V,E),V里结点的线性序列(Vi1,Vi2,……,Vin)称做一个拓扑序列,若此结点序列满足如下条件:若在有向图G中从结点Vi到结点Vj有一条路径,则在序列中结点Vi必在结点Vj之前。
任何无环的有向图,其结点都可以排在一个拓扑序列里,下面给出进行拓扑排序的方法:(1)从图中选择一个入度为0的结点且输出之。
(2)从图中删掉次结点及其所有的出边。
反复执行这两个步骤,直到所有的结点都输出了,也就是整个拓扑排序完成了,或者直到剩下的图中再也没有入度为0的结点,这就说明此图是有环图,拓扑排序不能再进行下去了。
其抽象算法可以表示为:TopSort(G){//优先输出无前趋的顶点while(G中有人度为0的顶点)do{从G中选择一个人度为0的顶点v且输出之;从G中删去v及其所有出边;}if(输出的顶点数目<|V(G)|)//若此条件不成立,则表示所有顶点均已输出,排序成功。
Error("G中存在有向环,排序失败!");}拓扑排序可以在有向图不同的存储表示上实现。
且每个图的拓扑序列并不唯一,即一个图有多个拓扑序列。
若有向图用邻接表法表示,则可以大大提高进行拓扑排序的效率。
在结点表里每个结点加进一个in字段,其内容是该结点的入度,这样,不用检查n*n的矩阵,只要检查n个元素的数组就能找出入度为0的结点,进一步我们用入度为0的结点的in字段构造一个链接方式存储的栈,把所有入度为0的结点都推入栈中,于是每次找入度为0的结点不必检查整个结点表,只要从栈顶取一个结点就行了。
对于从栈顶托出的入度为0的结点,检查它的出边表,对每条出边的终点,把它在结点表里对应的表目的in字段值减1,若某个结点的入度减为0了,就把它推到栈里去。
用这样的方法进行拓扑排序,初始地建立入度为0的结点的栈检查所有结点一次,排序中每个结点输出一次,每条边被检查一次,执行时间为O(n+m)。
2.4 有向图的逆拓扑排序无环的有向图的顶点一定在拓扑排序中。
与拓扑排序的思想恰好相反,逆拓扑排序是依次输出出度为0的点。
当有向图中无环时,可以利用深度优先遍历进行逆拓扑排序。
由于图中无环,从图中的某点出发进行深度优先搜索遍历时,最先推出DFS函数的顶点即是出度为0的顶点,它是拓扑有序序列中的最后一个顶点。
由此按推出DFS函数的先后记录下来的顶点序列即为逆向的拓扑序列(逆拓扑序列)。
在对该算法求精时,可用逆邻接表作为G的存储结构。
设置一个向量outdegree[0.. 或在逆邻接表的定点表结点中增加1个出度域来保存各顶点当前的出度;设置一个栈或一个队列来暂存所有出度为0的顶点。
除了增加一个栈或相邻向量T来保存输出的顶点序列外,该算法完全类似于拓扑排序。
抽象算法描述算法的抽象描述为:NonTopSort(G){//优先输出无后继的顶点while(G中有出度为0的顶点)do {从G中选一出度为0的顶点v且输出v;从G中删去v及v的所有人边}if(输出的顶点数目<|V(G)|)Error("G中存在有向环,排序失败!");}3 详细设计逆拓扑排序的结果只需要将所得到的拓扑排序反过来即可。
故编程序的重点在于得到有向图的拓扑排序。
3.1有向图的拓扑排序3.1.1 邻接表存储分析课题的要求首先则需要一个有向图,因而需要构建一个有向图,其中包括图的各种信息,有弧数,顶点数,有向边的起点与终点。