拓扑排序课程设计报告Word下载.docx
《拓扑排序课程设计报告Word下载.docx》由会员分享,可在线阅读,更多相关《拓扑排序课程设计报告Word下载.docx(20页珍藏版)》请在冰豆网上搜索。
1.能够求解该有向无环图的拓扑排序并输出出来;
2.拓扑排序应该能处理出现环的情况;
3.顶点信息要有几种情况可以选择。
1.2课程设计要求
1.输出拓扑排序数据外,还要输出邻接表数据;
2.参考相应的资料,独立完成课程设计任务;
3.交规范课程设计报告和软件代码。
2课程设计原理
2.1课设题目粗略分析
本课设题目要求编写算法能够建立有向无环图,有向无环图,顾名思义,即一个无环的有向图,是一类较有向图更一般的特殊有向图。
其功能要求及个人在写程序时对该功能的实现作如下分析:
1.将图以合适的方式存储起来。
图有多种存储方式,其中最常用的存储方式有图的邻接矩阵和邻接表。
本人在构思时使用邻接表来建立有向无环图,将其存储起来;
2.求解该有向无环图的拓扑排序,并将其输出出来。
若通过构造,建立了一个有向无环图,那么一定可以求出其拓扑排序,其原理比较简单。
即统计每个节点的入度,将入度为0的结点提取出来,然后再统计剩下的结点的入度,再次将入度为零的结点提取出来,以此类推,这样就形成了一个序列,这样的序列就是该图的拓扑排序序列;
3.拓扑排序算法应能够处理出现环的情况。
个人在写程序时,考虑到构造图时,会有构造成有向有环图的情况,应该在运行程序时,试着统计依次按照入读为零的节点输出的节点数是否为整个节点的总数,如果是,那么拓扑排序成功,输出拓扑排序的结果,否者输出“有环出现”;
4.输出除拓扑排序外,还要求输出邻接表数据。
由于图是用邻接表存储的,所以将邻接表按照顺序依次打印输出。
2.2原理图介绍
2.2.1功能模块图
图2.1功能模块图
2.2.2流程图分析
1.如图2.2所示,根据题目要求建立一个有向无环图,按照提示,依次输入节点数和变数,然后输入两个联通的节点<
u,v>
,前者指向后者,当输入边数为所要输入的数目时,输入结束,有向图建立完成(未判断是否有环)。
开始
建立有向无环图
j<
n
结束
j=j+1
输入节点数i,边数n,j=0
输入确定弧的两点
N
Y
图2.2建立有向无环图
2.如图2.3所示,判断有向图是否为有向无环图。
按照输入的有向图建立一个邻接表,将图储存在邻接表中,并将邻接表打印,然后对该邻接表进行拓扑排序,依次取入度为零的节点,入栈,并删除该节点和该节点有关的所边,若入栈节点个数与节点数相同,则全部入栈,该图为无环图,可以进行拓扑排序,若该图节点数大于入栈节点数,则该图为有环图。
建立邻接表并打印
取入度为零的节点入栈,删除该节点,继续遍历其他节点
入栈节点数等于节点总数
该图为无环图
该图为有环图
图2.3判断是否为无环图
3.此时该图为有向无环图,可进行拓扑排序,在上一过程中,所有节点已经入栈,将栈顶弹出进入另一个空栈,,然后依次输出栈顶,拓扑排序成功。
如图2.4所示。
将栈顶依次输出
拓扑排序成功
将弹出的栈顶进入新的空栈
输出栈顶元素
图2.4输出拓扑排序结果
4.具体内容
-
符合条件?
根据输入信息建立邻接表
建栈
寻找入度为零的节点入栈
弹出栈顶,打印,将与栈顶元素邻接的节点入度减一
栈是否为空
输入节点及弧的信息
-图2.5拓扑排序
3数据结构分析
3.1存储结构
一个无环的有向图叫做有向无环图,简称DAG图。
本算法首先要建立一个有向无环图,即通过输入各边的数据,搭建图的结构。
对于图的存储,用到邻接表,是一种链式存储结构。
弧结点结构类型:
typedefstructArcNode
{
intadjvex;
/*该弧指向的顶点的位置*/
structArcNode*nextarc;
/*指向下一条弧的指针*/
}ArcNode;
邻接表头结点类型:
typedefstructVNode
intdata;
/*顶点信息*/
ArcNode*firstarc;
/*指向第一条依附于该点的弧的指针*/
}VNode,AdjList[MAX_VEXTEX_NUM];
3.2算法描述
1.邻接表的构建
创建一个邻接表,首先要输入节点数和边数,然后输入确定一条边的两个节点,通过输入顺序来确定边的方向,构成有向图,具体方法如下:
初始化头结点
for(i=1;
i<
=G->
vexnum;
i++)
{
G->
vertices[i].data=i;
/*编写顶点的位置序号*/
vertices[i].firstarc=NULL;
}
先将头结点清零,编写顶点位置序号。
输入确定弧的两点,如果输入数字大于节点数或者小于零,则输出错误信息,并重新输入一组节点,申请新的节点来储存新的节点信息,该弧指向位置编号为m的节点,下一条弧指向的是依附于n的第一条弧,最后打印生成的邻接表。
for(i=1;
i<
arcnum;
printf("
\n输入确定弧的两个顶点u,v:
"
);
scanf("
%d%d"
&
n,&
m);
while(n<
0||n>
G->
vexnum||m<
0||m>
vexnum)
{
输入的顶点序号不正确请重新输入:
%d%d"
}
p=(ArcNode*)malloc(sizeof(ArcNode));
/*开辟新的弧结点*/
if(p==NULL)
ERROR!
exit
(1);
p->
adjvex=m;
/*该弧指向位置编号为m的结点*/
nextarc=G->
vertices[n].firstarc;
vertices[n].firstarc=p;
\n建立的邻接表为:
\n"
/*打印生成的邻接表(以一定的格式)*/
for(i=1;
i++)
%d"
G->
vertices[i].data);
for(p=G->
vertices[i].firstarc;
p;
p=p->
nextarc)
-->
p->
adjvex);
邻接表构建完成。
2.入栈操作
在本算法中栈主要用来构造拓扑排序序列。
由于栈具有先入后出的特点,所以,将每次选择入度为零的结点入栈,这样当结点都入栈的时候,再依次出栈,进入另一个新栈,这样,排序序列显而易见。
它将图这样的非线性结构转化为栈这样的线性结构。
建立空栈
typedefstruct
int*base;
/*栈底指针*/
int*top;
/*栈顶指针*/
intstacksize;
}SqStack;
初始化栈
voidInitStack(SqStack*S)
S->
base=(int*)malloc(STACK_INIT_SIZE*sizeof(int));
if(!
S->
base)/*存储分配失败*/
{
top=S->
base;
stacksize=STACK_INIT_SIZE;
}
入栈操作,压入新的元素为栈顶,e为新的栈顶元素。
voidPush(SqStack*S,inte)/*压入新的元素为栈顶*/
if(S->
top-S->
base>
=S->
stacksize)
base=(int*)realloc(S->
base,(S->
stacksize+STACKINCREMENT)*sizeof(int));
base)
base+S->
stacksize;
stacksize+=STACKINCREMENT;
*S->
top++=e;
3.拓扑排序
本程序的拓扑排序,必须在图的邻接表已知的情况下。
它还有另外一个功能:
判断一个图是不是无环图。
确切的说,不能单纯的叫拓扑排序,但考虑它主要的作用,在不引起误解的情况下就叫拓扑排序算法。
判断一个图是否为有向无环图并进行拓扑排序,对于本题目来说,由于本题要求是对有向无环图进行拓扑排序,其主要方法是将入度为零的结点依次输出出来,知道图的所有定点全部输出为止。
那么若图为有环图,在环上的结点在其他结点都选择出来后,入度都不为零,即无法被输出出来。
那么就可以认为按照拓扑排序的方法输出结点后,若不是将节点全部输出出来的,则此图为有环图。
输出有向图有环,拓扑排序失败。
若无环,则进行拓扑排序。
通过入栈出栈的操作来完成拓扑排序。
主要算法如下:
voidTopoSort(ALGraphG)
{intindegree[M];
inti,k,n;
intcount=0;
/*初始化输出计数器*/
ArcNode*p;
SqStackS;
FindInDegree(G,indegree);
InitStack(&
S);
=G.vexnum;
i++)/*入度为0的入栈*/
{if(!
indegree[i])
Push(&
S,i);
\n拓扑排序序列为:
while(!
StackEmpty(&
S))/*栈不为空*/
Pop(&
S,&
n);
/*弹出栈顶*/
%4d"
G.vertices[n].data);
/*输出栈顶并计数*/
count++;
for(p=G.vertices[n].firstarc;
p!
=NULL;
{
k=p->
adjvex;
(--indegree[k]))/*若入度减为零,则再入栈*/
{
S,k);
}
}
}
if(count<
G.vexnum){printf("
有向图中有环"
else{printf("
排序成功!
4调试与分析
4.1调试过程
在调试程序是主要遇到一下几类问题:
1.数组的数据容易出现混乱,比如节点用数字标识,数组结点的位置是从0开始,而标识符往往从1开始,这在程序的开始就应该注意到;
2.各函数的形参和实参的区别,全局变量,局部变量的区别,特别是在做大型程