拓扑排序(算法与数据结构课程设计)
拓扑排序-数据结构

拓扑排序问题描述:若用有向网表示教学计划,其中顶点表示某门课程,有向边表示课程之间的先修关系(如果A课程是B课程的先修课程,那么A到B之间有一条有向边从A 指向B)。
试设计一个教学计划编制程序,获取一个不冲突的线性的课程教学流程。
(课程线性排列,每门课上课时其先修课程已经被安排)。
基本要求:(1)输入参数:课程总数,每门课的课程号(固定占3位的字母数字串)和直接先修课的课程号。
(2)若根据输入条件问题无解,则报告适当的信息;否则将教学计划输出到用户指定的文件中。
需求分析:(测试数据加强版)1、输入形式:第一行是是个整数t,表示有t组测试数据;每一组测试数据的第一行是一个整数n,表示结点数目接下来的n行是n个顶点的信息接下来的一行是一个整数m,表示有向边的数目接下来是m行数据每一行是一条有向边的起止结点信息2、输出形式:如果可以实现拓扑排序,输出其得到的合法线性序列否则,输出“Input Error!”;3、功能描述:帮助判断当前的课程是否可以安排得当;如果得当,输出一个合法的修读顺序;4、样例输入输出:输入:25MathEnglishPhysicsChineseMusic5Math EnglishMath PhysicsEnglish ChinesePhysic ChineseChinese Music5MathEnglishPhysicsChineseMusic4Math EnglishMath PhysicsEnglish ChinesePhysic Chinese输出:Input Error!Math English Physics Chinese Music抽象数据结构类型描述(ADT):采用邻接表的方式来存储数据:抽象数据类型描述:Typedef struct Arc * link;struct Arc{Int adjvex;//邻接点编号Char info[15];//存储结点信息Link nextarc;//指向下一个邻接点};Struct Vex{Char info; //顶点信息Int indgree;//顶点的入度Link firstarc; //指向下一个邻接点};概要设计:算法主题思想:<1>、在有向图中选择一个没有前驱的顶点,输出之;<2>、从有向图中删除该顶点和所有以该顶点为尾的边;<3>、重复上述步骤,直到全部顶点都已经输出了或者图中剩下的顶点都不满足上述的两个条件位置。
算法与数据结构课设(有向图,无向图,有向网,无向网)

算法与数据结构课程设计报告系(院):计算机科学学院专业班级:教技1001姓名:李##学号: ******### 指导教师:***设计时间:2012.6.16 - 2012.6.24设计地点:4号楼2号机房目录一、设计方案 (1)二、实现过程以及代码 (2)三、测试 (20)四、结论和分析 (23)五、难点和收获 (23)一、 设计方案1.程序设计基本过程:拿到课程设计任务书,按照要求,需要设计有向图、有向网、无向图 、无向网四种图,以及邻接矩阵、邻接表两种数据存储结构,三层以上的显示菜单。
图的操作中又包含了有关线性表、栈和队列的基本操作。
由于显示菜单已给出,剩下的任务就是把函数写入其中。
2.程序流程图:预定义 定义结构体 定义变量 各种函数3.程序设计的原理:图的操作都是以两种存储结构为基础的:邻接矩阵存储结构和邻接表存储结构,如有向图,有向网,无向图,无向网的创建,其他的操作都是在四种图创建后才开始进行的。
所以,首先必须理解两种存储结构的定义。
图的邻接矩阵存储结构即图的数组表示法。
用两个数组分别存储数据元素(如顶点)的信息和数据元素之间的关系(如边或弧)的信息。
用邻接矩阵存储结构的图具有以下几点特征:(一):顶点数:vexnum ,边(弧)数:arcnum ,图的种类:kind ;(二):邻接矩阵:arcs(1顶点关系类型:adj 2相关信息:*info);(三):顶点向量(顶点名):vexs[];其优点是以二维数组表示有n 个顶点的图时,需存放n 个顶点的信息和n*n 条弧的信息存储量。
借助邻接矩阵容易判定任意两个顶点之间是否有边或弧相连,并容易求出各个顶点的度。
缺点是时间复杂度是O (n*n ),例如,构造一个具有n 个顶点和e 条边的无向网的时间复杂度为O (n*n+e*n )。
图的邻接表存储结构是图的一种链式存储结构。
对图中的每个顶点建立一个单链表,每个结点由三个域组成,邻接点域adjvex (弧尾在邻接表链表中的位序),链域nextarc (下一条弧),数据域info(权值)。
求拓扑序列排序课程设计

求拓扑序列排序课程设计一、教学目标本课程的教学目标是让学生掌握拓扑序列排序的基本概念、原理和应用,培养学生运用拓扑序列排序解决问题的能力。
具体包括以下三个方面的目标:1.知识目标:(1)理解拓扑序列排序的定义和性质;(2)掌握拓扑排序算法及其实现;(3)了解拓扑序列排序在实际应用中的重要性。
2.技能目标:(1)能够运用拓扑排序解决简单的问题;(2)能够运用图论知识分析和解决拓扑排序相关问题;(3)能够运用编程语言实现拓扑排序算法。
3.情感态度价值观目标:(1)培养学生对计算机科学的兴趣和热情;(2)培养学生团队合作、自主学习的能力;(3)培养学生运用所学知识解决实际问题的意识。
二、教学内容本课程的教学内容主要包括以下几个部分:1.拓扑序列排序的基本概念:图、顶点、边、度数、入度、出度等;2.拓扑排序的原理:拓扑排序的定义、拓扑排序的存在性、拓扑排序的算法;3.拓扑排序算法实现:深度优先搜索(DFS)算法、广度优先搜索(BFS)算法;4.拓扑排序的应用:任务调度、项目规划等实际问题。
三、教学方法为了达到本课程的教学目标,将采用以下几种教学方法:1.讲授法:通过讲解拓扑序列排序的基本概念、原理和应用,使学生掌握相关知识;2.讨论法:学生分组讨论拓扑排序算法实现和应用问题,培养学生的思考和表达能力;3.案例分析法:分析实际应用中的拓扑排序问题,让学生学会将理论知识应用于实际问题;4.实验法:安排拓扑排序算法的编程实验,培养学生的动手能力和实际问题解决能力。
四、教学资源为了支持本课程的教学内容和教学方法的实施,将准备以下教学资源:1.教材:《图论与算法导论》;2.参考书:《计算机网络》、《数据结构与算法》;3.多媒体资料:PPT课件、教学视频;4.实验设备:计算机、网络设备。
通过以上教学资源的使用,丰富学生的学习体验,提高学生的学习效果。
五、教学评估本课程的教学评估将采取多元化、全过程的方式进行,以全面、客观、公正地评价学生的学习成果。
数据结构之的拓扑排序算法拓扑排序算法的实现和性能分析

数据结构之的拓扑排序算法拓扑排序算法的实现和性能分析数据结构之拓扑排序算法拓扑排序算法的实现和性能分析拓扑排序是一种常用的图算法,用于对有向无环图(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表示边数。
三、总结拓扑排序是一种常用的图算法,可以对有向无环图进行排序。
求拓扑排序序列课程设计

求拓扑排序序列课程设计一、教学目标本节课的教学目标是让学生掌握拓扑排序序列的概念、性质和求解方法,能够运用拓扑排序解决实际问题。
具体分为以下三个部分:1.知识目标:学生能够理解拓扑排序的定义,了解拓扑排序的性质和应用场景,掌握拓扑排序的求解方法。
2.技能目标:学生能够运用拓扑排序解决实际问题,如任务调度、项目规划等,提高问题解决的效率。
3.情感态度价值观目标:培养学生对计算机科学和图论的兴趣,培养学生的逻辑思维和创新能力。
二、教学内容本节课的教学内容主要包括以下三个方面:1.拓扑排序的定义和性质:介绍拓扑排序的定义,解释拓扑排序的性质,如无环性、唯一性等。
2.拓扑排序的求解方法:讲解拓扑排序的求解方法,如DFS、BFS等,并通过实例进行演示。
3.拓扑排序的应用:介绍拓扑排序在实际问题中的应用,如任务调度、项目规划等,并通过实例进行讲解。
三、教学方法为了提高学生的学习兴趣和主动性,本节课将采用以下教学方法:1.讲授法:讲解拓扑排序的定义、性质和求解方法,为学生提供系统的知识结构。
2.案例分析法:通过分析实际问题,让学生了解拓扑排序的应用,提高学生的解决问题的能力。
3.实验法:让学生动手实践,求解实际问题,培养学生的实际操作能力。
四、教学资源为了支持教学内容和教学方法的实施,丰富学生的学习体验,我们将准备以下教学资源:1.教材:为学生提供系统的知识结构,方便学生课后复习。
2.多媒体资料:通过动画、图片等形式,直观地展示拓扑排序的概念和性质,提高学生的学习兴趣。
3.实验设备:为学生提供实际操作的机会,培养学生的实际操作能力。
五、教学评估本节课的评估方式包括以下几个方面:1.平时表现:通过观察学生在课堂上的参与程度、提问回答等情况,评估学生的学习态度和理解程度。
2.作业:布置相关的拓扑排序题目,评估学生对拓扑排序概念和求解方法的理解和应用能力。
3.考试:设计考试题目,全面考察学生对拓扑排序的定义、性质、求解方法和应用的掌握程度。
数据结构之拓扑排序算法详解

数据结构之拓扑排序算法详解拓扑排序算法是一种常用于有向无环图(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. 任务调度:在一个任务依赖关系图中,拓扑排序可以确定任务的执行顺序,保证所有任务按照依赖关系正确执行。
课程设计拓扑排序摘要

课程设计拓扑排序摘要一、教学目标本课程的教学目标是使学生掌握拓扑排序的基本概念和方法,能够运用拓扑排序解决实际问题。
具体分为以下三个部分:1.知识目标:学生需要理解拓扑排序的定义、特点和应用场景,掌握拓扑排序算法的实现和优化。
2.技能目标:学生能够运用拓扑排序算法解决基本的图论问题,如任务调度、课程安排等。
3.情感态度价值观目标:通过学习拓扑排序,学生能够培养逻辑思维能力、问题解决能力和创新意识,提高对计算机科学和图论的兴趣。
二、教学内容本课程的教学内容主要包括拓扑排序的定义和性质、拓扑排序算法的实现和优化、拓扑排序的应用场景。
具体安排如下:1.第一章:拓扑排序的定义和性质,介绍拓扑排序的基本概念和特点,分析拓扑排序的性质和限制。
2.第二章:拓扑排序算法的实现和优化,讲解常见的拓扑排序算法,如Kahn算法和Dijkstra算法,探讨算法的效率和优化方法。
3.第三章:拓扑排序的应用场景,介绍拓扑排序在任务调度、课程安排等实际问题中的应用,并通过案例分析让学生掌握拓扑排序的运用。
三、教学方法为了激发学生的学习兴趣和主动性,本课程将采用多种教学方法相结合的方式进行教学。
具体包括:1.讲授法:通过讲解拓扑排序的基本概念、算法和应用,使学生掌握拓扑排序的理论基础。
2.案例分析法:通过分析实际问题案例,让学生了解拓扑排序在实际中的应用和解决问题的方式。
3.实验法:安排课后实验,让学生动手实现拓扑排序算法,培养学生的实际操作能力和问题解决能力。
四、教学资源为了支持教学内容和教学方法的实施,丰富学生的学习体验,我们将准备以下教学资源:1.教材:选择一本关于图论和拓扑排序的经典教材,作为学生学习的基础资料。
2.参考书:提供一些相关领域的参考书籍,供学生深入学习和拓展知识。
3.多媒体资料:制作PPT、教学视频等多媒体资料,帮助学生更好地理解和掌握拓扑排序的知识。
4.实验设备:准备计算机实验室,让学生能够进行课后实验和实践操作。
拓扑排序课程设计报告

沈阳航空航天大学课程设计报告课程设计名称:数据结构课程设计课程设计题目:拓扑排序算法院(系):计算机学院专业:计算机科学与技术(嵌入式系统方向)班级:14010105班学号:2011040101221姓名:王芃然指导教师:丁一军目录1 课程设计介绍 (1)1.1课程设计内容 (1)1.2课程设计要求 (1)2 课程设计原理 (2)2.1课设题目粗略分析 (2)2.2原理图介绍 (2)2.2.1 功能模块图 (2)2.2.2 流程图分析 (3)3 数据结构分析 (7)3.1存储结构 (7)3.2算法描述 (7)4 调试与分析 (12)4.1调试过程 (12)4.2程序执行过程 (12)参考文献 (14)附录(关键部分程序清单) (15)1 课程设计介绍1.1 课程设计内容由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
若在图一的有向图上人为的加一个表示V2<=V3的弧(“<=”表示V2领先于V3)则图一表示的亦为全序且这个全序称为拓扑有序,而由偏序定义得到拓扑有序的操作便是拓扑排序。
在AOV网中为了更好地完成工程,必须满足活动之间先后关系,需要将各活动排一个先后次序即为拓扑排序。
编写算法建立有向无环图,主要功能如下:1.能够求解该有向无环图的拓扑排序并输出出来;2.拓扑排序应该能处理出现环的情况;3.顶点信息要有几种情况可以选择。
1.2 课程设计要求1.输出拓扑排序数据外,还要输出邻接表数据;2.参考相应的资料,独立完成课程设计任务;3.交规范课程设计报告和软件代码。
2 课程设计原理2.1 课设题目粗略分析本课设题目要求编写算法能够建立有向无环图,有向无环图,顾名思义,即一个无环的有向图,是一类较有向图更一般的特殊有向图。
其功能要求及个人在写程序时对该功能的实现作如下分析:1. 将图以合适的方式存储起来。
图有多种存储方式,其中最常用的存储方式有图的邻接矩阵和邻接表。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
拓扑排序一、问题描述在AOV网中为了更好地完成工程,必须满足活动之间先后关系,需要将各活动排一个先后次序即为拓扑排序。
拓扑排序可以应用于教学计划的安排,根据课程之间的依赖关系,制定课程安排计划。
按照用户输入的课程数,课程间的先后关系数目以及课程间两两间的先后关系,程序执行后会给出符合拓扑排序的课程安排计划。
二、基本要求1、选择合适的存储结构,建立有向无环图,并输出该图;2、实现拓扑排序算法;3、运用拓扑排序实现对教学计划安排的检验。
三、算法思想1、采用邻接表存储结构实现有向图;有向图需通过顶点数、弧数、顶点以及弧等信息建立。
2、拓扑排序算法void TopologicalSort(ALGraph G) 中,先输出入度为零的顶点,而后输出新的入度为零的顶点,此操作可利用栈或队列实现。
考虑到教学计划安排的实际情况,一般先学基础课(入度为零),再学专业课(入度不为零),与队列先进先出的特点相符,故采用队列实现。
3、拓扑排序算法void TopologicalSort(ALGraph G),大体思想为:1)遍历有向图各顶点的入度,将所有入度为零的顶点入队列;2)队列非空时,输出一个顶点,并对输出的顶点数计数;3)该顶点的所有邻接点入度减一,若减一后入度为零则入队列;4)重复2)、3),直到队列为空,若输出的顶点数与图的顶点数相等则该图可拓扑排序,否则图中有环。
4、要对教学计划安排进行检验,因此编写了检测用户输入的课程序列是否是拓扑序列的算法void TopSortCheck(ALGraph G),大体思想为:1)用户输入待检测的课程序列,将其存入数组;2)检查课程序列下一个元素是否是图中的顶点(课程),是则执行3),否则输出“课程XX不存在”并跳出;3)判断该顶点的入度是否为零,是则执行4),否则输出“入度不为零”并跳出;4)该顶点的所有邻接点入度减一;5)重复2)、3)、4)直到课程序列中所有元素均被遍历,则该序列是拓扑序列,否则不是拓扑序列。
四、数据结构1、链式队列的存储类型为:typedef int ElemType;typedef struct QNode{ ElemType data;struct QNode *next;} QNode,*QueuePtr;typedef struct{ QueuePtr front;QueuePtr rear;} LinkQueue;2、图的类型(邻接表存储结构)为:typedef char VertexType[20];//顶点信息(名称)typedef struct ArcNode//链表结点{ int vexpos;//该弧所指向的顶点在数组中的位置struct ArcNode *next;//指向当前起点的下一条弧的指针} ArcNode;typedef struct VNode//头结点{ VertexType name;//顶点信息(名称)int indegree;//顶点入度ArcNode *firstarc;//指向当前顶点的第一条弧的指针} VNode,AdjList[MAX_VERTEX_NUM];typedef struct{ AdjList vexhead;//邻接表头结点数组int vexnum,arcnum;//图的顶点数和弧数} ALGraph;五、模块划分1、链式队列操作1) void InitQueue(LinkQueue *Q)功能:初始化链式队列参数:*Q 待初始化的队列2) int QueueEmpty(LinkQueue Q)功能:判断空队列参数:Q 待判断的队列返回值:队列为空返回 1;队列非空返回 03) void EnQueue(LinkQueue *Q, ElemType e)功能:元素入队列参数:*Q 待操作的队列;e 要入队列的元素4) void DeQueue(LinkQueue *Q, ElemType *e)功能:元素出队列参数:*Q 待操作的队列;*e 记录出队列元素的变量2、有向图(DAG)邻接表存储结构(ALG)的操作1) int LocateVex(ALGraph G,VertexType v)功能:顶点在头结点数组中的定位参数:G 待操作的图;v 要在图中定位的顶点返回值:顶点存在则返回在头结点数组中的下标;否则返回图的顶点数2) int CreateGraph(ALGraph *G)功能:建立图函数内包含了由用户输入顶点数、弧数、顶点以及弧的操作参数:*G 待操作的图返回值:图建立成功返回1;图建立失败返回0错误判断:包含顶点数、弧数是否正确的判断;包含用户输入的弧的顶点是否存在的判断3) void PrintGraph(ALGraph G)功能:输出有向图参数:G 待输出的图4) int CreateGraph2(ALGraph *G)功能:建立预置课程图(输出函数内预置课程信息,并自动建立有向图)参数:*G 待操作的图返回值:图建立成功返回1;图建立失败返回0错误判断:包含顶点数、弧数是否正确的判断包含弧的顶点是否存在的判断5) void PrintGraph2(ALGraph G)功能:输出预置课程图参数:G 待输出的图3、拓扑排序及拓扑检测算法1) void TopologicalSort(ALGraph G)功能:实现拓扑排序参数:G 待进行拓扑排序的图错误判断:包含有向图是否有环的判断2) void TopSortCheck(ALGraph G)功能:运用拓扑排序的思想检测教学计划函数内包含了由用户输入待检测的课程序列的操作参数:G 待操作的图错误判断:包含用户输入的课程是否存在的判断包含不是拓扑序列的原因(该课程有多少个先决课程未学)4、主函数void main()功能:主函数利用while语句和switch语句实现菜单化调用函数六、源程序#include "stdlib.h"#include "stdio.h"#include "string.h"/*******************************************//* 以下为链式队列操作 *//*******************************************//* 定义链式队列类型 */typedef int ElemType;typedef struct QNode{ ElemType data;struct QNode *next;} QNode,*QueuePtr;typedef struct{ QueuePtr front;QueuePtr rear;} LinkQueue;/* 1.初始化链式队列 */void InitQueue(LinkQueue *Q){ Q->front=Q->rear=(QueuePtr)malloc(sizeof(QNode));if (!(Q->front)) exit(0);Q->front->next=NULL; }/* 2.判断空队列 */int QueueEmpty(LinkQueue Q){ if(Q.front==Q.rear)return 1;elsereturn 0; }/* 3.入队列 */void EnQueue(LinkQueue *Q, ElemType e){ QueuePtr p;p=(QueuePtr)malloc(sizeof(QNode));if (!p) exit(0);p->data=e; p->next=NULL;Q->rear->next=p;Q->rear=p; }/* 4.出队列 */void DeQueue(LinkQueue *Q, ElemType *e){ QueuePtr p;if(Q->front!=Q->rear){ p=Q->front->next;*e=p->data;Q->front->next=p->next;if (Q->rear==p) Q->rear=Q->front;free(p); }}/****************************************************//* 以下为有向图(DAG)邻接表存储结构(ALG)的操作 *//****************************************************/#define MAX_VERTEX_NUM 20 //最大顶点个数typedef char VertexType[20]; //顶点信息(名称)/* 图的类型定义(邻接表存储结构) */typedef struct ArcNode //链表结点{ int vexpos; //该弧所指向的顶点在数组中的位置struct ArcNode *next; //指向当前起点的下一条弧的指针} ArcNode;typedef struct VNode //头结点{ VertexType name; //顶点信息(名称)int indegree; //顶点入度ArcNode *firstarc; //指向当前顶点的第一条弧的指针} VNode,AdjList[MAX_VERTEX_NUM];typedef struct{ AdjList vexhead; //邻接表头结点数组int vexnum,arcnum; //图的顶点数和弧数} ALGraph;/* 5.顶点在头结点数组中的定位 */int LocateVex(ALGraph G,VertexType v){ int i;for(i=0;i<G.vexnum;i++)if(strcmp(v,G.vexhead[i].name)==0) break;return i; }/* 6.建立图(邻接表) */int CreateGraph(ALGraph *G) //成功建立返回1,不成功则返回0 { int i,j,k; VertexType v1,v2;ArcNode *newarc;printf("\n输入有向图顶点数和弧数vexnum,arcnum:"); //输入顶点数和弧数scanf("%d,%d",&(*G).vexnum,&(*G).arcnum); //输入并判断顶点数和弧数是否正确if((*G).vexnum<0||(*G).arcnum<0||(*G).arcnum>(*G).vexnum*((*G).vexnum-1)) { printf("\n顶点数或弧数不正确,有向图建立失败!\n");return 0; } printf("\n输入 %d 个顶点:",(*G).vexnum); //输入顶点名称for(i=0;i<(*G).vexnum;i++){ scanf("%s",(*G).vexhead[i].name); }printf("\n顶点列表:\n共有%d个顶点: ",(*G).vexnum);//输出顶点名称for(i=0;i<(*G).vexnum;i++)printf("%s ",(*G).vexhead[i].name);for(i=0;i<(*G).vexnum;i++) //邻接表初始化{ (*G).vexhead[i].firstarc=NULL;(*G).vexhead[i].indegree=0;}printf("\n\n输入 %d 条边:vi vj\n",(*G).arcnum); //输入有向图的边for(k=0;k<(*G).arcnum;k++){ scanf("%s%s",v1,v2); //v1是弧的起点(先决条件),v2是弧的终点i=LocateVex(*G,v1);j=LocateVex(*G,v2); //定位顶点并判断顶点是否存在if(i>=(*G).vexnum){ printf("顶点%s不存在,有向图建立失败!\n",v1);return 0; } if(j>=(*G).vexnum){ printf("顶点%s不存在,有向图建立失败!\n",v2);return 0; } newarc=(ArcNode*)malloc(sizeof(ArcNode)); //前插法建顶点链表newarc->vexpos=j;if((*G).vexhead[i].firstarc==NULL){ newarc->next=NULL;(*G).vexhead[i].firstarc=newarc; }else{ newarc->next=(*G).vexhead[i].firstarc->next;(*G).vexhead[i].firstarc->next=newarc; }(*G).vexhead[j].indegree++; //对应顶点入度计数加1}printf("\n有向图建立成功!\n");return 1;}/* 7.按邻接表方式输出有向图 */void PrintGraph(ALGraph G){ int i;ArcNode *p;printf("\n输出有向图:\n");for(i=0; i<G.vexnum; i++){ printf("\n顶点:%s ",G.vexhead[i].name);printf("入度:%3d\n",G.vexhead[i].indegree);p=G.vexhead[i].firstarc;printf("邻接点:");while(p!=NULL){ printf("%s ",G.vexhead[p->vexpos].name);p=p->next; }printf("\n");}}//为避免演示时要输入过多数据,以下函数将课程编号、课程间的先后关系通过数组预置/* 8.建立预置课程图(邻接表) */int CreateGraph2(ALGraph *G) //成功建立返回1,不成功则返回0{ int i,j,k; VertexType v1,v2; ArcNode *newarc;VertexType SubjectName[12]={ "C1","C2","C3","C4", //课程名称"C5","C6","C7","C8","C9","C10","C11","C12" },RelationV1[16]={ "C1","C1","C2","C1", //基础课"C3","C4","C11","C5","C3","C3","C6","C9","C9","C9","C10","C11"},RelationV2[16]={ "C2","C3","C3","C4", //以上面课程为基础的课"C5","C5","C6","C7","C7","C8","C8","C10","C11","C12","C12","C12",};/* 输出本程序使用的课程及先后关系表 */printf("\n本程序预置了如下课程及先后关系:\n");printf("\n课程编号课程名称先决条件\n\C1 程序设计基础无\n\C2 离散数学 C1\n\C3 数据结构 C1,C2\n\C4 汇编语言 C1\n\C5 语言的设计和分析 C3,C4\n\C6 计算机原理 C11\n\C7 编译原理 C5,C3\n\C8 操作系统 C3,C6\n\C9 高等数学无\n\C10 线性代数 C9\n\C11 普通物理 C9\n\C12 数值分析 C9,C10,C1\n");system("PAUSE");(*G).vexnum=12; (*G).arcnum=16;if((*G).vexnum<0||(*G).arcnum<0||(*G).arcnum>(*G).vexnum*((*G).vexnum-1)) { printf("\n课程数或先后关系不正确,有向图建立失败!\n");return 0;} //判断课程数和弧数是否正确for(i=0;i<(*G).vexnum;i++){ strcpy((*G).vexhead[i].name,SubjectName[i]); }for(i=0;i<(*G).vexnum;i++) //邻接表初始化{ (*G).vexhead[i].firstarc=NULL;(*G).vexhead[i].indegree=0; }for(k=0;k<(*G).arcnum;k++){ strcpy(v1,RelationV1[k]); strcpy(v2,RelationV2[k]);i=LocateVex(*G,v1);j=LocateVex(*G,v2); //定位课程并判断课程是否存在if(i>=(*G).vexnum){ printf("课程%s不存在,有向图建立失败!\n",v1);return 0; } if(j>=(*G).vexnum){ printf("课程%s不存在,有向图建立失败!\n",v2);return 0; } newarc=(ArcNode*)malloc(sizeof(ArcNode)); //前插法建课程链表newarc->vexpos=j;if((*G).vexhead[i].firstarc==NULL){ newarc->next=NULL;(*G).vexhead[i].firstarc=newarc; }else{ newarc->next=(*G).vexhead[i].firstarc->next;(*G).vexhead[i].firstarc->next=newarc; }(*G).vexhead[j].indegree++; //对应课程入度计数加1}printf("\n有向图建立成功!\n");return 1;}/* 9.按邻接表方式输出预置课程图 */void PrintGraph2(ALGraph G){ int i;ArcNode *p;printf("\n输出有向图:\n");for(i=0; i<G.vexnum; i++){ printf("\n课程:%s ",G.vexhead[i].name);printf("入度:%3d\n",G.vexhead[i].indegree);p=G.vexhead[i].firstarc;printf("以本课程为基础的课程:");while(p!=NULL){ printf("%s ",G.vexhead[p->vexpos].name);p=p->next;}printf("\n");}}/**********************************//* 以下为拓扑排序算法 *//**********************************//* 10.拓扑排序 */void TopologicalSort(ALGraph G){ int i,k,count;ElemType e;ArcNode *p;LinkQueue Q; /*定义队列*/InitQueue(&Q);for(i=0; i<G.vexnum; i++) //零入度课程入队列if(!G.vexhead[i].indegree) EnQueue(&Q,i);count=0; //对输出课程计数变量初始化printf("\n\n\n以上课程的一个拓扑排序序列为:\n");while(!QueueEmpty(Q)){ DeQueue(&Q,&e); //先将入度为零的课程输出printf("%s ",G.vexhead[e].name);count++; //对输出的顶点计数for(p=G.vexhead[e].firstarc;p;p=p->next) //遍历当前课程的邻接点{ k=p->vexpos; //邻接点位置if(!(--G.vexhead[k].indegree)) //每个邻接点入度减1后若为零则入队列EnQueue(&Q,k);}}printf("\n");if(count<G.vexnum){ printf("\n该有向图有回路,无法完成拓扑排序!\n"); }}/**********************************//* 以下为拓扑检测算法 *//**********************************//* 11.运用拓扑排序的思想检测教学计划 */void TopSortCheck(ALGraph G){ int i,k; ArcNode *p; VertexType v,CheckList[12];//待检测序列TopologicalSort(G);printf("\n输入待检测的课程序列:\n");for(i=0; i<G.vexnum; i++) //输入待检测序列scanf("%s",CheckList[i]);for(i=0; i<G.vexnum; i++){ strcpy(v,CheckList[i]);k=LocateVex(G,v);if(k>=G.vexnum) //判断课程是否存在{ printf("课程%s不存在!\n",v);return; }if(G.vexhead[k].indegree!=0) //判断课程入度是否为零{ printf("学习课程%s时,还有%d门先决课程未学!\n",v,G.vexhead[k].indegree);printf("本课程序列不是拓扑序列\n\n");return; }else{ for(p=G.vexhead[LocateVex(G,v)].firstarc;p;p=p->next)//遍历此课程邻接点{ k=p->vexpos; //邻接点位置G.vexhead[k].indegree--;} //每个邻接点入度减1}}printf("本课程序列符合拓扑序列\n\n");}/*******************************************//* 12.主函数 *//*******************************************/void main(){ ALGraph G; int menu,menu2;while(1){printf("\n **********************************************\n");printf(" * 1.建立有向图并输出 *\n");printf(" * 2.建立有向图并求一个拓扑排序序列 *\n");printf(" * 3.检测用户输入的课程安排 *\n");printf(" * 4.清屏 *\n");printf(" * 5.退出 *\n");printf(" **********************************************\n");printf(" 请输入你的选择:");scanf("%d",&menu);switch(menu){case 1:if(CreateGraph(&G)){system("PAUSE");PrintGraph(G);}//有向图建成则执操作break;case 2:if(CreateGraph(&G)) //有向图建成则执操作{ system("PAUSE");PrintGraph(G);system("PAUSE");TopologicalSort(G); }break;case 3:if(CreateGraph2(&G)){ //有向图建成则执操作system("PAUSE");PrintGraph2(G); system("PAUSE");while(1){TopSortCheck(G);printf("\n ************************************\n");printf(" * 1.检测其他课程序列 *\n");printf(" * 2.完成检测 *\n");printf(" ************************************\n");printf(" 请输入你的选择:");scanf("%d",&menu2);if(menu2!=1) break; }}break;case 4:system("CLS");break;case 5:return;}}}七、测试数据1、对“建立有向图并输出”的测试1) 正确的有向图信息顶点数和弧数:4,3顶点:A B C D边: A B B C C D2) 错误的边顶点数和弧数:4,3顶点:A B C D边: A B B C C E3) 错误的顶点数或弧数顶点数和弧数:3,72、对“建立有向图并求一个拓扑排序序列”的测试1) 有向图能实现拓扑排序顶点数和弧数:5,5顶点:A B C D E边:A D D C C B E A E C2) 有向图不能实现拓扑排序顶点数和弧数:5,5顶点:A B C D E边:A D D C C B E A B A3、对“检测用户输入的课程安排”的测试1) 课程序列符合拓扑序列课程序列:C9 C10 C11 C6 C1 C12 C4 C2 C3 C5 C7 C8 2) 课程序列中有课程不存在课程序列:C9 C10 C11 C6 C1 C12 C4 C2 C13 C5 C7 C8 3) 课程序列不是拓扑序列课程序列:C9 C10 C11 C1 C8 C6 C12 C4 C2 C3 C5 C7八、测试情况程序初始执行界面(以下测试编号与本文第七节测试数据编号一一对应)1、对“建立有向图并输出”的测试1) 正确的有向图信息有向图信息正确的情况下,程序显示“有向图建立成功”,并输出有向图。