数据结构-拓扑排序介绍
拓扑排序序列的步骤

拓扑排序序列的步骤拓扑排序是一种常用的有向图排序算法,它可以用来解决依赖关系的排序问题。
拓扑排序序列指的是通过拓扑排序算法得到的图中节点的一个线性排序。
在本文中,我们将深入探讨拓扑排序的步骤并给出实现示例。
一、拓扑排序简介拓扑排序适用于有向无环图(DAG)。
它的基本思想是将有向图中的节点按照依赖关系排序,使得每个节点的所有前驱节点都在它的前面。
如果存在环路,则无法进行拓扑排序。
二、拓扑排序步骤1. 初始化一个队列,用于储存入度为0的节点。
2. 遍历图中的所有节点,并统计每个节点的入度,将入度为0的节点加入队列。
3. 从队列中取出一个节点,将其输出,并将其所有邻接节点的入度减1。
4. 如果邻接节点的入度变为0,则将其加入队列。
5. 重复步骤3和步骤4,直到队列为空。
6. 如果输出的节点数量与图中节点的数量相同,则拓扑排序成功;否则,说明图中存在环路,无法进行拓扑排序。
示例代码如下:```pythondef topological_sort(graph):indegree = [0] * len(graph)queue = []# 统计每个节点的入度for node in graph:for adjacent in graph[node]: indegree[adjacent] += 1 # 将入度为0的节点加入队列 for i in range(len(indegree)):if indegree[i] == 0:queue.append(i)result = []while queue:node = queue.pop(0)result.append(node)# 将邻接节点的入度减1 for adjacent in graph[node]:indegree[adjacent] -= 1if indegree[adjacent] == 0: queue.append(adjacent) # 判断是否成功拓扑排序if len(result) == len(graph):return resultelse:return []# 图的邻接表表示graph = {0: [1, 2],1: [3, 4],2: [3],3: [],4: [3]}result = topological_sort(graph)if result:print("拓扑排序序列为:", result)else:print("图中存在环路,无法进行拓扑排序")```以上代码实现了拓扑排序的步骤,可以根据具体需求进行调用和扩展。
数据结构的应用的拓扑排序与关键路径算法

数据结构的应用的拓扑排序与关键路径算法拓扑排序与关键路径算法是数据结构中重要的应用之一。
拓扑排序通过对有向图的节点进行排序,使得对于任意一条有向边(u,v),节点 u 在排序中都出现在节点 v 之前。
关键路径算法则是用来确定一个项目的关键活动和最短完成时间。
拓扑排序的实现可以通过深度优先搜索或者广度优先搜索来完成。
深度优先搜索是递归地访问节点的所有未访问过的邻居节点,直到没有未访问过的邻居节点为止,然后将该节点添加到拓扑排序的结果中。
广度优先搜索则是通过使用队列来实现的,将节点的邻居节点逐个入队并进行访问,直到队列为空为止。
无论使用哪种方法,拓扑排序都可以通过判断节点的入度来进行。
拓扑排序在很多实际问题中都有广泛应用。
比如在任务调度中,拓扑排序可以用来确定任务间的依赖关系和执行顺序;在编译原理中,拓扑排序可以用来确定程序中变量的定义和使用顺序。
关键路径算法用于确定项目中的关键活动和最短完成时间。
它通过计算每个活动的最早开始时间和最晚开始时间,以及每个活动的最早完成时间和最晚完成时间来实现。
具体步骤如下:1. 构建有向加权图,其中节点表示项目的活动,有向边表示活动间的先后关系,边的权重表示活动的持续时间。
2. 进行拓扑排序,确定活动的执行顺序。
3. 计算每个活动的最早开始时间,即从起始节点到该节点的最长路径。
4. 计算每个活动的最晚开始时间,即从终止节点到该节点的最长路径。
5. 根据每个活动的最早开始时间和最晚开始时间,可以确定关键活动,即最早开始时间与最晚开始时间相等的活动。
6. 计算整个项目的最短完成时间,即从起始节点到终止节点的最长路径。
拓扑排序与关键路径算法在工程管理、任务调度、生产流程优化等领域都有重要应用。
它们能够帮助我们有效地组织和管理复杂的项目,提高工作效率和资源利用率。
在实际应用中,我们可以借助计算机编程以及各种图算法库来实现这些算法,从而更快速、准确地解决实际问题。
综上所述,拓扑排序与关键路径算法是数据结构的重要应用之一。
图的拓扑排序算法

图的拓扑排序算法图是计算机科学中常用的数据结构之一,它由一些节点(点)和连接这些节点的边(线)组成。
在计算机科学中,图经常被用来解决很多问题,例如计算机网络路由、调度、自然语言处理等等。
其中,图的拓扑排序算法是一个十分重要且广泛应用的算法。
在本文中,我们将详细介绍图的拓扑排序算法的原理及应用。
一、拓扑排序算法简介首先,我们来了解一下什么是拓扑排序算法。
拓扑排序是指将有向无环图(Directed Acyclic Graph, DAG)中节点按照拓扑序列排列的过程。
拓扑序列是指,在排列中,如果存在一条从节点A到节点B的路径,那么在拓扑序列中节点A必须出现在节点B之前。
如果存在环路,则不存在拓扑序列。
拓扑排序算法通常用于任务调度等场景中。
在计算机科学中,拓扑排序算法可以使用两种方法进行实现:基于搜索的算法和基于入度的算法。
二、基于搜索的算法基于搜索的算法是一种比较直接的实现思路,我们可以使用深度优先搜索或者广度优先搜索来实现。
深度优先搜索的方法是,先访问图中入度为0的节点,将其加入拓扑序列中,并将其后继节点的入度减1,直到遍历完整幅图。
基于入度的算法基于入度的算法是另一种有用的实现思路。
首先,我们可以记录每个节点的入度值。
入度是指图中所有指向该节点的边的个数。
对于一个拓扑序列中的节点,它的入度必定为0。
因此,我们可以将入度为0的节点放入队列中,然后对该节点的后继节点的入度减1。
如果减去入度后某个节点的入度为0,则也将其加入队列中。
不断循环这一过程,直到遍历完整幅图。
三、应用场景拓扑排序算法可以在很多场景中应用。
例如,任务调度。
在计算机中,任务调度是指将一些任务分配给不同的处理器进行处理的过程。
我们可以将每个任务看作一个节点,处理器看作边。
拓扑排序算法可以帮助我们找到一个最优的任务调度方案。
另一个应用场景是编译器和依赖管理器。
在编译一个程序时,我们需要按指定顺序编译不同的模块。
如果模块之间存在依赖关系,则需要使用拓扑排序算法来进行模块的编译顺序优化。
数据结构之的拓扑排序算法拓扑排序算法的实现和性能分析

数据结构之的拓扑排序算法拓扑排序算法的实现和性能分析数据结构之拓扑排序算法拓扑排序算法的实现和性能分析拓扑排序是一种常用的图算法,用于对有向无环图(DAG)进行排序。
拓扑排序的主要应用包括任务调度、编译顺序、依赖关系管理等方面。
本文将介绍拓扑排序算法的实现及其性能分析。
一、拓扑排序算法的实现拓扑排序算法一般采用深度优先搜索(DFS)或广度优先搜索(BFS)来实现。
下面将以DFS实现为例进行介绍。
1. 创建图数据结构在进行拓扑排序之前,首先需要创建图的数据结构。
可以使用邻接表或邻接矩阵来表示图。
以邻接表为例,可以使用一个字典来表示每个节点和其相邻节点的关系。
2. 初始化标记数组为了保证每个节点只被访问一次,需要使用一个标记数组来记录节点的访问状态。
可以使用布尔数组或整数数组来表示,将未访问的节点标记为false或0,已访问的节点标记为true或1。
3. 实现拓扑排序函数拓扑排序函数的主要功能是对图进行遍历,并将节点按照拓扑排序的顺序输出。
拓扑排序函数通常使用递归的方式实现。
4. 输出排序结果拓扑排序算法完成后,可以将排序的结果输出。
按照拓扑排序的定义,输出的结果应该是一个拓扑有序的节点列表。
二、拓扑排序算法的性能分析拓扑排序算法的性能取决于图的规模和结构。
下面将从时间复杂度和空间复杂度两个方面进行性能分析。
1. 时间复杂度分析拓扑排序算法的时间复杂度主要取决于图的节点数和边数。
在最坏情况下,每个节点都需要遍历一次,而每个节点的边数是有限的,所以拓扑排序的时间复杂度为O(V+E),其中V表示节点数,E表示边数。
2. 空间复杂度分析拓扑排序算法的空间复杂度主要取决于存储图和标记数组的空间。
在使用邻接表表示图时,需要额外的空间来存储每个节点及其相邻节点的关系。
同时,需要使用标记数组来记录节点的访问状态。
所以拓扑排序的空间复杂度为O(V+E+V),即O(V+E),其中V表示节点数,E表示边数。
三、总结拓扑排序是一种常用的图算法,可以对有向无环图进行排序。
数据结构之拓扑排序算法详解

数据结构之拓扑排序算法详解拓扑排序算法是一种常用于有向无环图(DAG)的排序算法,它可以将图中的顶点按照一定的顺序进行排序,使得图中任意一条有向边的起点在排序结果中都排在终点的前面。
在实际应用中,拓扑排序算法常用于解决任务调度、依赖关系分析等问题。
本文将详细介绍拓扑排序算法的原理、实现方法以及应用场景。
### 一、拓扑排序算法原理拓扑排序算法的原理比较简单,主要包括以下几个步骤:1. 从DAG图中选择一个入度为0的顶点并输出。
2. 从图中删除该顶点以及以该顶点为起点的所有有向边。
3. 重复步骤1和步骤2,直到图中所有顶点都被输出。
### 二、拓扑排序算法实现下面以Python语言为例,给出拓扑排序算法的实现代码:```pythondef topological_sort(graph):in_degree = {v: 0 for v in graph}for u in graph:for v in graph[u]:in_degree[v] += 1queue = [v for v in graph if in_degree[v] == 0] result = []while queue:u = queue.pop(0)result.append(u)for v in graph[u]:in_degree[v] -= 1if in_degree[v] == 0:queue.append(v)if len(result) == len(graph):return resultelse:return []# 测试代码graph = {'A': ['B', 'C'],'B': ['D'],'C': ['D'],'D': []}print(topological_sort(graph))```### 三、拓扑排序算法应用场景拓扑排序算法在实际应用中有着广泛的应用场景,其中包括但不限于以下几个方面:1. 任务调度:在一个任务依赖关系图中,拓扑排序可以确定任务的执行顺序,保证所有任务按照依赖关系正确执行。
数据结构拓扑排序实验报告

数据结构拓扑排序实验报告正文:一、实验目的本实验旨在通过实现拓扑排序算法来加深对数据结构中图的相关概念的理解,掌握拓扑排序的具体步骤与实现方法。
二、实验原理拓扑排序是一种对有向无环图进行排序的算法,它可以将有向无环图的顶点按照线性的顺序排列出来,使得对于任何一个有向边(u, v),都有顶点 u 在排列中出现在顶点 v 之前。
拓扑排序常用于表示图中的依赖关系,如任务调度、编译顺序等场景。
三、实验步骤1. 构建有向图根据实际需求构建有向图,可以使用邻接表或邻接矩阵等数据结构来表示有向图。
2. 执行拓扑排序算法利用拓扑排序算法对构建的有向图进行排序,可选择使用深度优先搜索(DFS)或广度优先搜索(BFS)等算法实现。
3. 输出排序结果将排序后的顶点按照线性的顺序输出,得到拓扑排序的结果。
四、实验结果与分析1. 实验数据以图 G = (V, E) 的顶点集合 V 和边集合 E,构建了如下的有向图:V = {A, B, C, D, E, F}E = {(A, C), (B, C), (C, D), (D, E), (E, F)}2. 拓扑排序结果经过拓扑排序算法的处理,得到的拓扑排序结果如下: A, B, C, D, E, F3. 结果分析可以看出,根据有向图的依赖关系,拓扑排序算法能够将顶点按照合理的顺序进行排序。
拓扑排序的结果可以作为图中顶点的执行顺序,具有重要的应用价值。
五、实验总结通过本次实验,我们深入学习了拓扑排序算法,并成功实现了拓扑排序的过程。
拓扑排序在图论和数据结构中具有广泛的应用,对于理解和解决与图相关的问题具有重要意义。
六、附件本文档没有涉及附件内容。
七、法律名词及注释本文档没有涉及法律名词及注释。
拓扑数据结构的名词解释

拓扑数据结构的名词解释随着科技的快速发展,数据的规模和复杂度急剧增加,大数据和人工智能成为了当今世界的热点话题。
在处理如此庞大和复杂的数据时,拓扑数据结构扮演着重要的角色。
本文将对拓扑数据结构的相关术语进行解释,帮助读者更好地理解这一概念。
一、图 (Graph)图是拓扑数据结构的基础。
它由节点集合和边集合组成。
节点代表实体,边则表示节点之间的关系。
图可以用来描述各种各样的关系网络,如社交网络、交通网络等。
图可以分为有向图和无向图,有向图的边是有方向的,而无向图的边是无方向的。
二、节点 (Node)节点是图的基本元素,也称为顶点。
每个节点可以具有零个或多个关联的边,用来表示节点之间的关系。
节点可以包含数据、属性和其他相关信息。
三、边 (Edge)边是图中节点之间的连接线。
边可以是有向的,表示从一个节点到另一个节点的单向关系;也可以是无向的,表示两个节点之间的双向关系。
边可以具有权重,用来表示节点之间的关联强度或距离。
四、路径 (Path)路径是图中的一条连接序列,由一系列的边组成。
路径可以是闭合的,即起点和终点相同,形成环;也可以是非闭合的,连接不同的节点。
五、连通性 (Connectivity)连通性是指图中节点之间的关联程度。
一个图可以是强连通的,即任意两个节点之间都存在路径;也可以是弱连通的,即只有部分节点之间存在路径。
六、拓扑排序 (Topological Sorting)拓扑排序是对有向无环图进行排序的一种算法。
在一个有向图中,如果存在一条路径从节点 A 到节点 B,那么在排序结果中,节点 A 应该在节点 B 的前面。
拓扑排序可以用来解决任务调度、依赖关系等问题。
七、最短路径 (Shortest Path)最短路径是指在图中找到两个节点之间路径长度最短的路径。
最短路径算法可以用来解决如最优路径规划、网络路由等问题。
常见的最短路径算法包括迪杰斯特拉算法和弗洛伊德算法。
八、网络流 (Network Flow)网络流是指在图中沿着边进行的一种资源分配。
拓扑排序及关键路径

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、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
14信计2015-2016(一)数据结构课程设计设计题目拓扑排序设计时间2016.1.11——2016.1.15学生姓名冯佳君学生学号20140401105所在班级14信计1指导教师刘风华徐州工程学院数学与物理科学学院一、需求分析1.问题描述本次课程设计题目是:用邻接表构造图然后进行拓扑排序,输出拓扑排序序列。
拓扑排序的基本思想为:1)从有向图中选一个无前驱的顶点输出;2)将此顶点和以它为起点的弧删除;3) 重复1)、 2)直到不存在无前驱的顶点;4) 若此时输出的顶点数小于有向图中的顶点数,则说明有向图中存在回路,否则输出的顶点的顺序即为一个拓扑序列。
2.拓扑排序有向图拓朴排序算法的基本步骤如下:1)从图中选择一个入度为0的顶点,输出该顶点;2)从图中删除该顶点及其相关联的弧,调整被删弧的弧头结点的入度(入度-1);3)重复执行1)、2)直到所有顶点均被输出,拓朴排序完成或者图中再也没有入度为0的顶点(此种情况说明原有向图含有环)。
3.基本要求(1)输入的形式和输入值的范围;首先是输入要排序的顶点数和弧数,都为整型,中间用分隔符隔开;再输入各顶点的值,为正型,中间用分隔符隔开;然后输入各条弧的两个顶点值,先输入弧头,再输入弧尾,中间用分隔符隔开,输入的值只能是开始输入的顶点值否则系统会提示输入的值的顶点值不正确,请重新输入,只要继续输入正确的值就行。
(2)输出的形式;首先输出建立的邻接表,然后是最终各顶点的出度数,再是拓扑排序的序列,并且每输出一个顶点,就会输出一次各顶点的入度数。
(3) 程序所能达到的功能;因为该程序是求拓扑排序,所以算法的功能就是要输出拓扑排序的序列,在一个有向图中,若用顶点表示活动,有向边就表示活动间先后顺序,那么输出的拓扑序列就表示各顶点间的关系为反映出各点的存储结构,以邻接表存储并输出各顶点的入度。
二、概要设计1. 算法中用到的所有各种数据类型的定义在该程序中用邻接表作为图的存储结构。
首先,定义表结点和头结点的结构类型,然后定义图的结构类型。
创建图用邻接表存储的函数,其中根据要求输入图的顶点和边数,并根据要求设定每条边的起始位置,构建邻接表依次将顶点插入到邻接表中。
拓扑排序的函数在该函数中首先要对各顶点求入度,其中要用到求入度的函数,为了避免重复检测入度为零的顶点,设置一个辅助栈,因此要定义顺序栈类型,以及栈的函数:入栈,出栈,判断栈是否为空。
2.各程序模块之间的层次调用关系第一部分,void ALGraph *G函数构建图,用邻接表存储。
这个函数没有调用函数。
第二部分,void TopologicalSort(ALGraph *G)输出拓扑排序函数,这个函数首先调用FindInDegree(G,indegree)对各顶点求入度indegree[0……vernum-1];然后设置了一个辅助栈,调用InitStack(&S)初始化栈,在调用Push(&S,i)入度为0者进栈,while(!StackEmpty(&S))栈不为空时,调用Pop(&sS,&n)输出栈中顶点并将以该顶点为起点的边删除,入度indegree[k]--,当输出某一入度为0的顶点时,便将它从栈中删除。
第三部分,主函数,先后调用void CreatGraph(ALGraph *G)函数构建图、void TopologicalSort(ALGraph *G)函数输出拓扑排序实现整个程序。
3.设计的主程序流程(见附页)流程图::三、详细设计(实现概要设计中定义的所有数据类型,对每个操作写出伪码算法;对主程序和其他模块也都需要写出伪码算法(伪码算法达到的详细程度建议为;按照伪码算法可以在计算机键盘直接输入高级程序设计语言程序);写出出函数和过程的调用关系。
)1.实现概要设计中定义的所有数据类型#include<stdio.h>#include<stdlib.h>#define MAX_VEXTEX_NUM 100#define STACK_INIT_SIZE 100#define STACKINCREMENT 10#define OK 1#define M 100#define ERROR 0typedef int ElemType;typedef struct ArcNode{int adjvex;struct ArcNode *nextarc;}ArcNode;typedef struct VNode{int data;ArcNode *firstarc;}VNode,AdjList[MAX_VEXTEX_NUM];typedef struct{AdjList vertices;int vexnum, arcnum;}ALGraph;typedef struct{ElemType *base;ElemType *top;int stacksize;}SqStack;2.算法和各模块的代码程序中各函数算法思想如下:2.1 void InitStack(SqStack *S)初始化栈将栈的空间设为 STACK-INIT-SIZE。
2.2 int Pop(SqStack *S,ElemType *e)出栈操作,若站不空,删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR。
2.3 void Push(SqStack *S,ElemType e)进栈操作,插入元素e为新的栈顶元素。
2.4 int StackEmpty(SqStack *S)判断栈是否为空,语句if (S->top=S->base )判断,若栈不为空,则删除S 的栈顶元素,并返回OK;否则返回ERROR。
2.5 void CreatGraph (ALGraph *G)构建图,用邻接表存储,首先定义邻接表指针变量,输入顶点数和弧数,初始化邻接表,将表头向量域置空,输入存在弧的点集合,当输入顶点值超出输入值的范围就会出错,否则依次插入进邻接表,最后输出建立好的邻接表。
2.6 void FindInDegree(ALGrap G, int indegreee[])求入度操作,设一个存放各顶点入度的数组indegreee[],然后indegreee[i]=0赋初值,for循环indegreee[]++,存储入度数。
2.7 void TopologicalISort(ALGraph G)输出拓扑排序函数。
其思路是若G无回路,则输出G的顶点的一个拓扑序列并返回OK,否则返回ERROR。
首先由于邻接表的存储结构入度为零的顶点即为没有前驱的顶点,我们可以附设一个存放个顶点入度的数组,调用FindInDegree( G, indegreee[])对各顶点求入度;为了避免重复检测入度为零0的顶点,设置一个栈,调用InitStack(&S)初始化栈,在调用Push(&S,i)入度为0者进栈,while(!StackEmpty(&S))栈不为空时,调用Pop(&sS,&n)输出栈中顶点并将以该顶点为起点的边删除,入度indegree[k]--,当输出某一入度为0的顶点时,便将它从栈中删除。
3.算法的时间复杂度和空间复杂度拓扑排序实际是对邻接表表示的图G进行遍历的过程,每次访问一个入度为零的顶点,若图G中没有回路,则需扫描邻接表中的所有边结点,在算法开始时,为建立入度数组D需访问表头向量中的所有边结点,算法的时间复杂度为O(n+e)。
四、测试与分析输入:结果如下:五、总结拓扑排序就是对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若<u,v> ∈E(G),则u在线性序列中出现在v之前。
在进行课程设计中,更好的认识了拓扑排序。
理清了各个模块之间算法之间的条理。
认识了伪代码(Pseudocode)是一种算法描述语言。
使用伪代码的目的是为了使被描述的算法可以容易地以任何一种编程语言(Pascal,C,Java,etc)实现。
因此,伪代码必须结构清晰、代码简单、可读性好,并且类似自然语言。
介于自然语言与编程语言之间。
它是一种让人便于理解的代码。
不依赖于语言的,用来表示程序执行过程,而不一定能编译运行的代码。
在数据结构讲算法的时候用的很多。
在设计中,我们遇到了程序正确,却对某些无向图无法进行拓扑排序的问题。
多次对程序进行修改后,才可以进行拓扑排序。
问题出在调用函数的错误理解,模块之间的联系模糊不清。
附录:源程序:#include<stdio.h>#include<stdlib.h>#define MAX_VEXTEX_NUM 100#define STACK_INIT_SIZE 100#define STACKINCREMENT 10#define OK 1#define M 100#define ERROR 0typedef int ElemType;typedef struct ArcNode{int adjvex;struct ArcNode *nextarc;}ArcNode;typedef struct VNode{int data;ArcNode *firstarc;}VNode,AdjList[MAX_VEXTEX_NUM];typedef struct{AdjList vertices;int vexnum, arcnum;}ALGraph;typedef struct{ElemType *base;ElemType *top;int stacksize;}SqStack;void InitStack(SqStack *);int Pop(SqStack *, ElemType *);void Push(SqStack *,ElemType );int StackEmpty(SqStack *);void CreatGraph(ALGraph *);void FindInDegree(ALGraph , int * );void TopologicalSort(ALGraph );void InitStack(SqStack *S){S->base=(ElemType *)malloc(STACK_INIT_SIZE*sizeof(ElemType)); if(!S->base){printf("内存分配失败,请检查储存位置,再见");exit(1);}S->top=S->base;S->stacksize=STACK_INIT_SIZE;}int Pop(SqStack *S,ElemType *e){if(S->top==S->base){return ERROR;}*e=*--S->top;return 0;}void Push(SqStack *S,ElemType e){if(S->top-S->base>=S->stacksize){S->base = (ElemType *)realloc(S->base,(S->stacksize+STACKINCREMENT)*sizeof(ElemType)); if(!S->base){printf("内存分配失败,请检查储存位置,再见");exit(1);}S->top = S->base+S->stacksize;S->stacksize+=STACKINCREMENT;}*S->top++=e;}int StackEmpty(SqStack *S){if(S->top==S->base)return OK;elsereturn ERROR;}void CreatGraph(ALGraph *G){int m, n, i;ArcNode *p;printf("请输入顶点数和边数:");scanf("%d%d",&G->vexnum,&G->arcnum);for (i = 1; i <= G->vexnum; i++){G->vertices[i].data = i;G->vertices[i].firstarc = NULL;}for (i = 1; i <= G->arcnum; i++){printf("\n请输入存在边的两个顶点的序号,先输入弧尾,再输入弧头:"); scanf("%d%d",&n,&m);while (n < 0 || n > G->vexnum || m < 0 || m > G->vexnum){printf("输入的顶点序号不正确请重新输入:");scanf("%d%d",&n,&m);}p = (ArcNode*)malloc(sizeof(ArcNode));if (p == NULL){printf("内存分配失败,请检查储存位置,再见");exit(1);}p->adjvex = m;p->nextarc = G->vertices[n].firstarc;G->vertices[n].firstarc = p;}}void FindInDegree(ALGraph G, int indegree[]){int i;for (i = 1; i <= G.vexnum; i++){indegree[i] = 0;}for (i = 1; i <= G.vexnum; i++){while (G.vertices[i].firstarc){indegree[G.vertices[i].firstarc->adjvex]++;G.vertices[i].firstarc = G.vertices[i].firstarc->nextarc;}}}void TopologicalSort(ALGraph G){int indegree[M];int i, k, n,b,j=0;int a[20];int count = 0;ArcNode *p;SqStack S;FindInDegree(G, indegree);InitStack(&S);for ( i = 1; i <= G.vexnum; i++){if (!indegree[i])Push(&S,i);}while(!StackEmpty(&S)){Pop(&S,&n);a[j]=G.vertices[n].data;j++;count++;for (p = G.vertices[n].firstarc; p != NULL; p = p->nextarc) {k = p->adjvex;if (!(--indegree[k])){Push(&S,k);}}}printf("\n");if (count < G.vexnum){printf("该有向图有环\n");}else{printf("排序成功\n");printf("进行拓扑排序输出顺序为:"); for (b=0;b<j;b++){printf("%4d",a[b]);}printf("\n");}}int main(void){ALGraph G;CreatGraph(&G);TopologicalSort(G);system("pause");return 0;}。