拓扑排序.docx

上传人:小飞机 文档编号:3543899 上传时间:2023-03-13 格式:DOCX 页数:20 大小:44.27KB
返回 下载 相关 举报
拓扑排序.docx_第1页
第1页 / 共20页
拓扑排序.docx_第2页
第2页 / 共20页
拓扑排序.docx_第3页
第3页 / 共20页
拓扑排序.docx_第4页
第4页 / 共20页
拓扑排序.docx_第5页
第5页 / 共20页
亲,该文档总共20页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《拓扑排序.docx》由会员分享,可在线阅读,更多相关《拓扑排序.docx(20页珍藏版)》请在三一办公上搜索。

1、拓扑排序拓扑排序 一、问题描述 在AOV网中为了更好地完成工程,必须满足活动之间先后关系,需要将各活动排一个先后次序即为拓扑排序。拓扑排序可以应用于教学计划的安排,根据课程之间的依赖关系,制定课程安排计划。按照用户输入的课程数,课程间的先后关系数目以及课程间两两间的先后关系,程序执行后会给出符合拓扑排序的课程安排计划。 二、基本要求 1、选择合适的存储结构,建立有向无环图,并输出该图; 2、实现拓扑排序算法; 3、运用拓扑排序实现对教学计划安排的检验。 三、算法思想 1、采用邻接表存储结构实现有向图;有向图需通过顶点数、弧数、顶点以及弧等信息建立。 2、拓扑排序算法void Topologic

2、alSort(ALGraph G) 中,先输出入度为零的顶点,而后输出新的入度为零的顶点,此操作可利用栈或队列实现。考虑到教学计划安排的实际情况,一般先学基础课,再学专业课,与队列先进先出的特点相符,故采用队列实现。 3、拓扑排序算法void TopologicalSort(ALGraph G),大体思想为: 1)遍历有向图各顶点的入度,将所有入度为零的顶点入队列; 2)队列非空时,输出一个顶点,并对输出的顶点数计数; 3)该顶点的所有邻接点入度减一,若减一后入度为零则入队列; 4)重复2)、3),直到队列为空,若输出的顶点数与图的顶点数相等则该图可拓扑排序,否则图中有环。 4、要对教学计划安

3、排进行检验,因此编写了检测用户输入的课程序列是否是拓扑序列的算法void TopSortCheck(ALGraph G),大体思想为: 1)用户输入待检测的课程序列,将其存入数组; 2)检查课程序列下一个元素是否是图中的顶点,是则执行3),否则输出“课程XX不存在”并跳出; 3)判断该顶点的入度是否为零,是则执行4),否则输出“入度不为零”并跳出; 4)该顶点的所有邻接点入度减一; 5)重复2)、3)、4)直到课程序列中所有元素均被遍历,则该序列是拓扑序列,否则不是拓扑序列。 wilyes11收集 博客(与学习无关): 四、数据结构 1、链式队列的存储类型为: typedef int Elem

4、Type; typedef struct QNode ElemType data; struct QNode *next; QNode,*QueuePtr; typedef struct QueuePtr front; QueuePtr rear; LinkQueue; 2、图的类型为: typedef char VertexType20;/顶点信息 typedef struct ArcNode/链表结点 int vexpos;/该弧所指向的顶点在数组中的位置 struct ArcNode *next;/指向当前起点的下一条弧的指针 ArcNode; typedef struct VNode/

5、头结点 VertexType name;/顶点信息 int indegree;/顶点入度 ArcNode *firstarc;/指向当前顶点的第一条弧的指针 VNode,AdjListMAX_VERTEX_NUM; typedef struct AdjList vexhead;/邻接表头结点数组 int vexnum,arcnum;/图的顶点数和弧数 ALGraph; 五、模块划分 1、链式队列操作 1) void InitQueue(LinkQueue *Q) 功能:初始化链式队列 参数:*Q 待初始化的队列 2) int QueueEmpty(LinkQueue Q) 功能:判断空队列 参

6、数:Q 待判断的队列 返回值:队列为空返回 1;队列非空返回 0 3) void EnQueue(LinkQueue *Q, ElemType e) 功能:元素入队列 参数:*Q 待操作的队列;e 要入队列的元素 4) void DeQueue(LinkQueue *Q, ElemType *e) wilyes11收集 博客(与学习无关): 功能:元素出队列 参数:*Q 待操作的队列;*e 记录出队列元素的变量 2、有向图(DAG)邻接表存储结构(ALG)的操作 1) int LocateVex(ALGraph G,VertexType v) 功能:顶点在头结点数组中的定位 参数:G 待操作的

7、图;v 要在图中定位的顶点 返回值:顶点存在则返回在头结点数组中的下标;否则返回图的顶点数 2) int CreateGraph(ALGraph *G) 功能:建立图 函数内包含了由用户输入顶点数、弧数、顶点以及弧的操作 参数:*G 待操作的图 返回值:图建立成功返回1;图建立失败返回0 错误判断:包含顶点数、弧数是否正确的判断; 包含用户输入的弧的顶点是否存在的判断 3) void PrintGraph(ALGraph G) 功能:输出有向图 参数:G 待输出的图 4) int CreateGraph2(ALGraph *G) 功能:建立预置课程图 参数:*G 待操作的图 返回值:图建立成功

8、返回1;图建立失败返回0 错误判断:包含顶点数、弧数是否正确的判断 包含弧的顶点是否存在的判断 5) void PrintGraph2(ALGraph G) 功能:输出预置课程图 参数:G 待输出的图 3、拓扑排序及拓扑检测算法 1) void TopologicalSort(ALGraph G) 功能:实现拓扑排序 参数:G 待进行拓扑排序的图 错误判断:包含有向图是否有环的判断 2) void TopSortCheck(ALGraph G) 功能:运用拓扑排序的思想检测教学计划 函数内包含了由用户输入待检测的课程序列的操作 参数:G 待操作的图 错误判断:包含用户输入的课程是否存在的判断

9、wilyes11收集 博客(与学习无关): 包含不是拓扑序列的原因 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 QueuePt

10、r 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; else return 0; /* 3.入队列 */ void EnQueue(LinkQueue *Q, ElemT

11、ype e) QueuePtr p; p=(QueuePtr)malloc(sizeof(QNode); if (!p) exit(0); p-data=e; p-next=NULL; wilyes11收集 博客(与学习无关): 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

12、; free(p); /*/ /* 以下为有向图(DAG)邻接表存储结构(ALG)的操作 */ /*/ #define MAX_VERTEX_NUM 20 /最大顶点个数 typedef char VertexType20; /顶点信息 /* 图的类型定义 */ typedef struct ArcNode /链表结点 int vexpos; /该弧所指向的顶点在数组中的位置 struct ArcNode *next; /指向当前起点的下一条弧的指针 ArcNode; typedef struct VNode /头结点 VertexType name; /顶点信息 int indegree;

13、/顶点入度 ArcNode *firstarc; /指向当前顶点的第一条弧的指针 VNode,AdjListMAX_VERTEX_NUM; typedef struct AdjList vexhead; /邻接表头结点数组 int vexnum,arcnum; /图的顶点数和弧数 ALGraph; /* 5.顶点在头结点数组中的定位 */ int LocateVex(ALGraph G,VertexType v) int i; for(i=0;iG.vexnum;i+) if(strcmp(v,G.vexheadi.name)=0) break; return i; /* 6.建立图 */ i

14、nt CreateGraph(ALGraph *G) /成功建立返回1,不成功则返回0 int i,j,k; VertexType v1,v2;ArcNode *newarc; wilyes11收集 博客(与学习无关): printf(n输入有向图顶点数和弧数vexnum,arcnum:); /输入顶点数和弧数 scanf(%d,%d,&(*G).vexnum,&(*G).arcnum); /输入并判断顶点数和弧数是否正确 if(*G).vexnum0|(*G).arcnum(*G).vexnum*(*G).vexnum-1) printf(n顶点数或弧数不正确,有向图建立失败!n);retu

15、rn 0; printf(n输入 %d 个顶点:,(*G).vexnum); /输入顶点名称 for(i=0;i(*G).vexnum;i+) scanf(%s,(*G).vexheadi.name); printf(n顶点列表:n共有%d个顶点: ,(*G).vexnum);/输出顶点名称 for(i=0;i(*G).vexnum;i+) printf(%s ,(*G).vexheadi.name); for(i=0;i(*G).vexnum;i+) /邻接表初始化 (*G).vexheadi.firstarc=NULL; (*G).vexheadi.indegree=0; printf(n

16、n输入 %d 条边:vi vjn,(*G).arcnum); /输入有向图的边 for(k=0;k=(*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).vexheadi.firstarc=NULL) newarc-next=NULL; (*G).vexheadi.firstarc=n

17、ewarc; else newarc-next=(*G).vexheadi.firstarc-next; (*G).vexheadi.firstarc-next=newarc; (*G).vexheadj.indegree+; /对应顶点入度计数加1 printf(n有向图建立成功!n); return 1; /* 7.按邻接表方式输出有向图 */ void PrintGraph(ALGraph G) int i;ArcNode *p; printf(n输出有向图:n); for(i=0; ivexpos.name); p=p-next; printf(n); /为避免演示时要输入过多数据,以

18、下函数将课程编号、课程间的先后关系通过数组预置 /* 8.建立预置课程图 */ int CreateGraph2(ALGraph *G) /成功建立返回1,不成功则返回0 int i,j,k; VertexType v1,v2; ArcNode *newarc; VertexType SubjectName12= C1,C2,C3,C4, /课程名称 C5,C6,C7,C8, C9,C10,C11,C12 , RelationV116= C1,C1,C2,C1, /基础课 C3,C4,C11,C5, C3,C3,C6,C9, C9,C9,C10,C11, RelationV216= C2,C3

19、,C3,C4, /以上面课程为基础的课 C5,C5,C6,C7, C7,C8,C8,C10, C11,C12,C12,C12,; /* 输出本程序使用的课程及先后关系表 */ printf(n本程序预置了如下课程及先后关系:n); printf(n课程编号 课程名称 先决条件n C1 程序设计基础 无n C2 离散数学 C1n C3 数据结构 C1,C2n C4 汇编语言 C1n C5 语言的设计和分析 C3,C4n C6 计算机原理 C11n C7 编译原理 C5,C3n C8 操作系统 C3,C6n C9 高等数学 无n C10 线性代数 C9n C11 普通物理 C9n C12 数值分析

20、 C9,C10,C1n); system(PAUSE); (*G).vexnum=12; (*G).arcnum=16; if(*G).vexnum0|(*G).arcnum(*G).vexnum*(*G).vexnum-1) printf(n课程数或先后关系不正确,有向图建立失败!n); return 0; /判断课程数和弧数是否正确 for(i=0;i(*G).vexnum;i+) strcpy(*G).vexheadi.name,SubjectNamei); wilyes11收集 博客(与学习无关): for(i=0;i(*G).vexnum;i+) /邻接表初始化 (*G).vexhe

21、adi.firstarc=NULL; (*G).vexheadi.indegree=0; for(k=0;k=(*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).vexheadi.firstarc=NULL) newarc-next=NULL; (*G).vexheadi.first

22、arc=newarc; else newarc-next=(*G).vexheadi.firstarc-next; (*G).vexheadi.firstarc-next=newarc; (*G).vexheadj.indegree+; /对应课程入度计数加1 printf(n有向图建立成功!n); return 1; /* 9.按邻接表方式输出预置课程图 */ void PrintGraph2(ALGraph G) int i;ArcNode *p; printf(n输出有向图:n); for(i=0; ivexpos.name); p=p-next; printf(n); /*/ /* 以

23、下为拓扑排序算法 */ /*/ /* 10.拓扑排序 */ wilyes11收集 博客(与学习无关): void TopologicalSort(ALGraph G) int i,k,count;ElemType e;ArcNode *p; LinkQueue Q; /*定义队列*/ InitQueue(&Q); for(i=0; inext) /遍历当前课程的邻接点 k=p-vexpos; /邻接点位置 if(!(-G.vexheadk.indegree) /每个邻接点入度减1后若为零则入队列 EnQueue(&Q,k); printf(n); if(countG.vexnum) print

24、f(n该有向图有回路,无法完成拓扑排序!n); /*/ /* 以下为拓扑检测算法 */ /*/ /* 11.运用拓扑排序的思想检测教学计划 */ void TopSortCheck(ALGraph G) int i,k; ArcNode *p; VertexType v,CheckList12;/待检测序列 TopologicalSort(G); printf(n输入待检测的课程序列:n); for(i=0; iG.vexnum; i+) /输入待检测序列 scanf(%s,CheckListi); for(i=0; i=G.vexnum) /判断课程是否存在 printf(课程%s不存在!n

25、,v);return; if(G.vexheadk.indegree!=0) /判断课程入度是否为零 printf(学习课程%s时,还有%d门先决课程未学!n,v,G.vexheadk.indegree); printf(本课程序列不是拓扑序列nn);return; else for(p=G.vexheadLocateVex(G,v).firstarc;p;p=p-next)/遍历此课程邻接点 k=p-vexpos; /邻接点位置 wilyes11收集 博客(与学习无关): G.vexheadk.indegree-; /每个邻接点入度减1 printf(本课程序列符合拓扑序列nn); /*/

26、/* 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(

27、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); p

28、rintf( * 2.完成检测 *n); printf( *n); printf( 请输入你的选择:); scanf(%d,&menu2); if(menu2!=1) break; wilyes11收集 博客(与学习无关): break; case 4: system(CLS); break; case 5: return; 七、测试数据 1、对“建立有向图并输出”的测试 1) 正确的有向图信息 顶点数和弧数:4,3 顶点:A B C D 边: A B 2) 错误的边 顶点数和弧数:4,3 顶点:A B C D 边: A B B C C E B C C D 3) 错误的顶点数或弧数 顶点数和弧

29、数:3,7 2、对“建立有向图并求一个拓扑排序序列”的测试 1) 有向图能实现拓扑排序 顶点数和弧数:5,5 顶点:A B C D E 边:A D D C C B E A E C 2) 有向图不能实现拓扑排序 顶点数和弧数:5,5 顶点:A B C D E 边:A D D C C B E A B A 3、对“检测用户输入的课程安排”的测试 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) 课程序列不是拓扑

30、序列 wilyes11收集 博客(与学习无关): 课程序列:C9 C10 C11 C1 C8 C6 C12 C4 C2 C3 C5 C7 八、测试情况 程序初始执行界面 1、对“建立有向图并输出”的测试 1) 正确的有向图信息 有向图信息正确的情况下,程序显示“有向图建立成功”,并输出有向图。 2) 错误的边 本测试中,第三条边(C E)的一个顶点E不是有向图中的顶点,程序能判断本错误并显示相应的提示信息。 3) 错误的顶点数或弧数 本测试中,顶点数和弧数分别为3,7。若有向图共有n个顶点,两顶点间最多有2条有向边,则有向图最多有n*(n-1)条边。而3*(3-1)=67,故程序提示“顶点数或

31、弧数不正确,有向图建立失败”;程序还能判断负的顶点数和弧数。 2、对“建立有向图并求一个拓扑排序序列”的测试 1) 有向图能实现拓扑排序 wilyes11收集 博客(与学习无关): 有向图能实现拓扑排序的情况下,程序输出其中一个拓扑排序序列。 2) 有向图不能实现拓扑排序 本测试中,有向图其中四条边(A D)、(D C)、(C B)、(B A)构成环,程序能判断有向图有回路并提示相应信息。 3、对“检测用户输入的课程安排”的测试 程序首先输出预置的课程信息和据此建立的有向图。 wilyes11收集 博客(与学习无关): 1) 课程序列符合拓扑序列 在用户输入的课程序列符合拓扑序列的情况下,程序

32、提示“本课程序列符合拓扑序列”,并显示如图菜单。 2) 课程序列中有课程不存在 本程序预置了C1-C12共12门课程,若用户输入的课程序列中有不属于预置课程的课程,wilyes11收集 博客(与学习无关): 程序会提示“课程XX不存在!”,并显示如图菜单。 3) 课程序列不是拓扑序列 若用户输入的课程序列不是拓扑序列,程序会输出原因,即“学习课程XX时,还有X门先决课程未学!” ,并显示如图菜单。 九、参考文献 1、严蔚敏,数据结构,清华大学出版社。 2、谭浩强,C语言程序设计,清华大学出版社。 wilyes11收集 博客(与学习无关): 小结 平时我就比较爱好编程,有时候自己也会设想一些小程

33、序,然后通过自己的努力来实现。因此我把本次课程设计当作了又一次锻炼,拿到题目后,经过与组员的讨论便开始了程序的编写。 大家都知道,编程是一件很需要耐心的事。因为几乎每一个程序的编写,都需要学习新的知识才能进行,同时程序调试过程很枯燥,有时候一点小错意味着长时间的查错。如语法错误中,“;”丢失、“”与“”不匹配等问题最难定位到出错语句;逻辑错误中,作为循环变量的“i”与“j”相互混淆、对未分配空间的节点进行操作等,都会使程序运行出错而难以找到原因。算法设计、程序调试的过程中,经常遇到看似简单但又无法解决的问题,这时候很容易灰心丧气,此时切不可烦躁,一定要冷静的思考,认真的分析;而解决问题,完成程

34、序后,那种兴奋感与成就感也令人振奋。可以说编写程序既是一件艰苦的工作,又是一件愉快的事情。 我的小组课程设计题目的核心是“拓扑排序”。虽然平时对拓扑排序有一些了解,上课也学过,但真正应用到程序中,写出算法却一点也不简单。拓扑排序,首先需要有被排序的主体,也就是有向图,于是先要实现有向图的建立及相关操作;有向图的建立,该选取怎样的数据结构,是邻接矩阵还是邻接表,本着尽量靠近实际应用的态度,我选择了节省存储空间的邻接表;拓扑排序要将图中零入度顶点先输出,可利用栈或队列实现,而本程序的一个应用是实现教学计划的安排,考虑到教学计划安排的实际情况,一般先学各门基础课,再学专业课,与队列先进先出的特点相符

35、,故采用队列实现。总之,什么地方该用什么数据结构,该写出怎样的算法,都要经过精心分析和仔细考虑。 课程设计不是一个人的任务,而是一个小组三个成员共同的任务,不但要能完成程序,而且在完成的过程中也要让团队有效地协作起来。在本次课程设计的过程中,我认识到以下几点:第一,要有奉献精神,不要怕自己多做了,不要怕自己承担的任务有多重,而其他成员做的很少。多去做一点不会吃亏,还能学到更多的东西。团队成员之间应团结互助,不计功过得失;第二,分工上不能马虎,要具体到个人,每个人负责哪部分任务,什么时候完成,都要有明确的说明,应各尽其能,做到资源优化配置;第三,具体工作时,各成员应频繁交流,避免各自为政,最后导致函数功能不符要求,参数调用不方便,或是论文作者无从下手;第四,当工作出

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号