拓扑排序算法与数据结构课程设计.docx

上传人:b****5 文档编号:6772258 上传时间:2023-01-10 格式:DOCX 页数:20 大小:174.67KB
下载 相关 举报
拓扑排序算法与数据结构课程设计.docx_第1页
第1页 / 共20页
拓扑排序算法与数据结构课程设计.docx_第2页
第2页 / 共20页
拓扑排序算法与数据结构课程设计.docx_第3页
第3页 / 共20页
拓扑排序算法与数据结构课程设计.docx_第4页
第4页 / 共20页
拓扑排序算法与数据结构课程设计.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

拓扑排序算法与数据结构课程设计.docx

《拓扑排序算法与数据结构课程设计.docx》由会员分享,可在线阅读,更多相关《拓扑排序算法与数据结构课程设计.docx(20页珍藏版)》请在冰豆网上搜索。

拓扑排序算法与数据结构课程设计.docx

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

拓扑排序

一、问题描述

在AOV网中为了更好地完成工程,必须满足活动之间先后关系,需要将各活动排一个先后次序即为拓扑排序。

拓扑排序可以应用于教学计划的安排,根据课程之间的依赖关系,制定课程安排计划。

按照用户输入的课程数,课程间的先后关系数目以及课程间两两间的先后关系,程序执行后会给出符合拓扑排序的课程安排计划。

二、基本要求

1、选择合适的存储结构,建立有向无环图,并输出该图;

2、实现拓扑排序算法;

3、运用拓扑排序实现对教学计划安排的检验。

三、算法思想

1、采用邻接表存储结构实现有向图;有向图需通过顶点数、弧数、顶点以及弧等信息建立。

2、拓扑排序算法voidTopologicalSort(ALGraphG)中,先输出入度为零的顶点,而后输出新的入度为零的顶点,此操作可利用栈或队列实现。

考虑到教学计划安排的实际情况,一般先学基础课(入度为零),再学专业课(入度不为零),与队列先进先出的特点相符,故采用队列实现。

3、拓扑排序算法voidTopologicalSort(ALGraphG),大体思想为:

1)遍历有向图各顶点的入度,将所有入度为零的顶点入队列;

2)队列非空时,输出一个顶点,并对输出的顶点数计数;

3)该顶点的所有邻接点入度减一,若减一后入度为零则入队列;

4)重复2)、3),直到队列为空,若输出的顶点数与图的顶点数相等则该图可拓扑排序,否则图中有环。

4、要对教学计划安排进行检验,因此编写了检测用户输入的课程序列是否是拓扑序列的算法voidTopSortCheck(ALGraphG),大体思想为:

1)用户输入待检测的课程序列,将其存入数组;

2)检查课程序列下一个元素是否是图中的顶点(课程),是则执行3),否则输出“课程XX不存在”并跳出;

3)判断该顶点的入度是否为零,是则执行4),否则输出“入度不为零”并跳出;

4)该顶点的所有邻接点入度减一;

5)重复2)、3)、4)直到课程序列中所有元素均被遍历,则该序列是拓扑序列,否则不是拓扑序列。

四、数据结构

1、链式队列的存储类型为:

typedefintElemType;

typedefstructQNode

{ElemTypedata;

structQNode*next;

}QNode,*QueuePtr;

typedefstruct

{QueuePtrfront;

QueuePtrrear;

}LinkQueue;

2、图的类型(邻接表存储结构)为:

typedefcharVertexType[20];//顶点信息(名称)

typedefstructArcNode//链表结点

{intvexpos;//该弧所指向的顶点在数组中的位置

structArcNode*next;//指向当前起点的下一条弧的指针

}ArcNode;

typedefstructVNode//头结点

{VertexTypename;//顶点信息(名称)

intindegree;//顶点入度

ArcNode*firstarc;//指向当前顶点的第一条弧的指针

}VNode,AdjList[MAX_VERTEX_NUM];

typedefstruct

{AdjListvexhead;//邻接表头结点数组

intvexnum,arcnum;//图的顶点数和弧数

}ALGraph;

五、模块划分

1、链式队列操作

1)voidInitQueue(LinkQueue*Q)

功能:

初始化链式队列

参数:

*Q待初始化的队列

2)intQueueEmpty(LinkQueueQ)

功能:

判断空队列

参数:

Q待判断的队列

返回值:

队列为空返回1;队列非空返回0

3)voidEnQueue(LinkQueue*Q,ElemTypee)

功能:

元素入队列

参数:

*Q待操作的队列;e要入队列的元素

4)voidDeQueue(LinkQueue*Q,ElemType*e)

功能:

元素出队列

参数:

*Q待操作的队列;*e记录出队列元素的变量

2、有向图(DAG)邻接表存储结构(ALG)的操作

1)intLocateVex(ALGraphG,VertexTypev)

功能:

顶点在头结点数组中的定位

参数:

G待操作的图;v要在图中定位的顶点

返回值:

顶点存在则返回在头结点数组中的下标;否则返回图的顶点数

2)intCreateGraph(ALGraph*G)

功能:

建立图

函数内包含了由用户输入顶点数、弧数、顶点以及弧的操作

参数:

*G待操作的图

返回值:

图建立成功返回1;图建立失败返回0

错误判断:

包含顶点数、弧数是否正确的判断;

包含用户输入的弧的顶点是否存在的判断

3)voidPrintGraph(ALGraphG)

功能:

输出有向图

参数:

G待输出的图

4)intCreateGraph2(ALGraph*G)

功能:

建立预置课程图(输出函数内预置课程信息,并自动建立有向图)

参数:

*G待操作的图

返回值:

图建立成功返回1;图建立失败返回0

错误判断:

包含顶点数、弧数是否正确的判断

包含弧的顶点是否存在的判断

5)voidPrintGraph2(ALGraphG)

功能:

输出预置课程图

参数:

G待输出的图

3、拓扑排序及拓扑检测算法

1)voidTopologicalSort(ALGraphG)

功能:

实现拓扑排序

参数:

G待进行拓扑排序的图

错误判断:

包含有向图是否有环的判断

2)voidTopSortCheck(ALGraphG)

功能:

运用拓扑排序的思想检测教学计划

函数内包含了由用户输入待检测的课程序列的操作

参数:

G待操作的图

错误判断:

包含用户输入的课程是否存在的判断

包含不是拓扑序列的原因(该课程有多少个先决课程未学)

4、主函数

voidmain()

功能:

主函数

利用while语句和switch语句实现菜单化调用函数

六、源程序

#include"stdlib.h"

#include"stdio.h"

#include"string.h"

/*******************************************/

/*以下为链式队列操作*/

/*******************************************/

/*定义链式队列类型*/

typedefintElemType;

typedefstructQNode

{ElemTypedata;

structQNode*next;

}QNode,*QueuePtr;

typedefstruct

{QueuePtrfront;

QueuePtrrear;

}LinkQueue;

/*1.初始化链式队列*/

voidInitQueue(LinkQueue*Q)

{Q->front=Q->rear=(QueuePtr)malloc(sizeof(QNode));

if(!

(Q->front))exit(0);

Q->front->next=NULL;}

/*2.判断空队列*/

intQueueEmpty(LinkQueueQ)

{if(Q.front==Q.rear)

return1;

else

return0;}

/*3.入队列*/

voidEnQueue(LinkQueue*Q,ElemTypee)

{QueuePtrp;

p=(QueuePtr)malloc(sizeof(QNode));

if(!

p)exit(0);

p->data=e;p->next=NULL;

Q->rear->next=p;

Q->rear=p;}

/*4.出队列*/

voidDeQueue(LinkQueue*Q,ElemType*e)

{QueuePtrp;

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)的操作*/

/****************************************************/

#defineMAX_VERTEX_NUM20//最大顶点个数

typedefcharVertexType[20];//顶点信息(名称)

/*图的类型定义(邻接表存储结构)*/

typedefstructArcNode//链表结点

{intvexpos;//该弧所指向的顶点在数组中的位置

structArcNode*next;//指向当前起点的下一条弧的指针

}ArcNode;

typedefstructVNode//头结点

{VertexTypename;//顶点信息(名称)

intindegree;//顶点入度

ArcNode*firstarc;//指向当前顶点的第一条弧的指针

}VNode,AdjList[MAX_VERTEX_NUM];

typedefstruct

{AdjListvexhead;//邻接表头结点数组

intvexnum,arcnum;//图的顶点数和弧数

}ALGraph;

/*5.顶点在头结点数组中的定位*/

intLocateVex(ALGraphG,VertexTypev)

{inti;

for(i=0;i

if(strcmp(v,G.vexhead[i].name)==0)break;

returni;}

/*6.建立图(邻接表)*/

intCreateGraph(ALGraph*G)//成功建立返回1,不成功则返回0

{inti,j,k;VertexTypev1,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");return0;}

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条边:

vivj\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);return0;}if(j>=(*G).vexnum)

{printf("顶点%s不存在,有向图建立失败!

\n",v2);return0;}

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");

return1;

}

/*7.按邻接表方式输出有向图*/

voidPrintGraph(ALGraphG)

{inti;ArcNode*p;

printf("\n输出有向图:

\n");

for(i=0;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.建立预置课程图(邻接表)*/

intCreateGraph2(ALGraph*G)//成功建立返回1,不成功则返回0

{inti,j,k;VertexTypev1,v2;ArcNode*newarc;

VertexTypeSubjectName[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");

return0;}//判断课程数和弧数是否正确

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);return0;}

if(j>=(*G).vexnum)

{printf("课程%s不存在,有向图建立失败!

\n",v2);return0;}

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");

return1;

}

/*9.按邻接表方式输出预置课程图*/

voidPrintGraph2(ALGraphG)

{inti;ArcNode*p;

printf("\n输出有向图:

\n");

for(i=0;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.拓扑排序*/

voidTopologicalSort(ALGraphG)

{inti,k,count;ElemTypee;ArcNode*p;

LinkQueueQ;/*定义队列*/

InitQueue(&Q);

for(i=0;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

{printf("\n该有向图有回路,无法完成拓扑排序!

\n");}

}

/**********************************/

/*以下为拓扑检测算法*/

/**********************************/

/*11.运用拓扑排序的思想检测教学计划*/

voidTopSortCheck(ALGraphG)

{inti,k;ArcNode*p;VertexTypev,CheckList[12];//待检测序列

TopologicalSort(G);

printf("\n输入待检测的课程序列:

\n");

for(i=0;i

scanf("%s",CheckList[i]);

for(i=0;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->v

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

当前位置:首页 > PPT模板 > 中国风

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1