数据结构课程设计说明书 基于邻接矩阵的图的遍历Word文档下载推荐.docx
《数据结构课程设计说明书 基于邻接矩阵的图的遍历Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计说明书 基于邻接矩阵的图的遍历Word文档下载推荐.docx(17页珍藏版)》请在冰豆网上搜索。
实验证明,两种算法的遍历结果截然不同,但均能完成对图的遍历过程。
在课程设计中,程序设计设计语言运行环境为VisualC++,程序运行平台为windowsXP。
summary:
Themainpurposeofthiscoursedesignistounderstandgraphtraversalproblemsfurtherandweshouldlearnhowtochangetheinputdiagramintoadjacencymatrixstorage,andrealizegraphdepth-firsttraversal(DFS)andbreadth-firsttraversal(BFS),basedontheadjacencymatrix.Theexperimentalresultsprovethattheresultsofthetwoalgorithm'
sergodicarequitedifferent,butallcancompletethegraphtraversalprocess.Inthecurriculumdesign,programdesignlanguageisrunningintheenvironmentofVisualc++.ProgramoperationplatformisWindowsXP.
关键字:
图、存储结构、邻接矩阵、遍历。
Keywords:
Diagram、storagestructure、adjacencymatrix、ergodic.
1引言
图论在现代计算机科学中占有举足轻重的地位,而许多的图论问题需要在图中遍历来寻找某个特定的结构,图的遍历算法从而变得十分重要。
图是一种较为复杂且重要的数据结构,其特殊性在于图形结构中结点之间的关系可以是任意的,图中任意两个数据元素之间都有可能相关。
就本课程设计而言应用图论的知识讨论如何在计算机上实现图的遍历的操作,主要解决图的遍历的两种算法即广度优选遍历和深度优选遍历的实现。
从图的定义可知,一个图的信息包括两个部分,即图中的顶点信息及描述图的顶点间的关系——边或者弧的信息。
因此,无论采用什么样的方法建立图的存储结构都应该保证图的信息的准确性和完整性。
关于图的存储,有邻接矩阵和邻接表法,我们在此使用邻接矩阵法来作为图的存储结构。
2需求分析
2.1设计目的
①巩固和加深学生对C语言、数据结构课程的基本知识的理解和掌握。
②掌握C语言编程和程序调试的基本技能。
③利用C语言进行基本的软件设计。
④掌握书写程序设计说明文档的能力。
⑤提高运用C语言、数据结构解决实际问题的能力。
⑥了解图的存储结构,掌握并灵活应用图的算法。
⑦熟练掌握图的两种搜索路径的遍历算法。
2.2设计任务
以邻接矩阵为存储结构编写程序,设计出的系统应具备的以下功能:
根据输入建立基于邻接矩阵的图,并实现图的深度优先,广度优先遍历算法,输出原图结构及遍历结果。
2.3基本操作
2.3.1程序调用的基本函数
StatusInitQueue(LinkQueue*Q)操作结果:
初始化队列
StatusQueueEmpty(LinkQueueQ)操作结果:
判断队列是否为空
StatusEnQueue(LinkQueue*Q,QElemTypee)操作结果:
入队列
StatusDeQueue(LinkQueue*Q,QElemType*e)操作结果:
出队列
voidCreateGraph(MGraph*G)操作结果:
以邻接矩阵为存储结构创建图。
voidPrintGraph(MGraphG)操作结果:
邻接矩阵方式输出无向图
Dfs(MGraphG,intv)操作结果:
对已存在的图进行深度优先遍历。
BfsTraverse(MGraphG)操作结果:
对已存在的图进行广度优先遍历。
2.3.2各函数的调用关系图
3数据结构设计
3.1队列
3.1.1队列的类型定义
typedefintQElemType;
typedefstructQNode
{QElemTypedata;
structQNode*next;
}QNode,*QueuePtr;
QNode是队列中的每个节点元素的结构类型
3.1.2循环队列的存储结构
typedefstruct
{
QueuePtrfront;
QueuePtrrear;
}LinkQueue;
LinkQueue是一个队列,是用于广度遍历的辅助队列,一般先将队列置空,根结点入队列,队列非空,获得队列首节点,当前节点出队列,再访问当前节点。
3.2基于邻接矩阵的图(MGraph)
3.2.1图的类型定义
typedefstructArcCell
{VRTypeadj;
/*图中有1/0表示是否有边,网中表示边上的权值*/
/*InfoType*info;
与边相关的信息*/
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
3.2.2图的结构
{VertexTypevexs[MAX_VERTEX_NUM];
/*顶点向量*/
AdjMatrixarcs;
/*邻接矩阵*/
intvexnum,arcnum;
/*图中当前顶点数和边数*/
}MGraph;
MGraph是基于邻接矩阵的图的结构。
其中Vertextype是顶点集;
AdjMatrix是边集,也是邻接矩阵;
vexnum,arcnum分别是顶点的总数和边的总数,用于初始化图.
4算法设计
4.1邻接矩阵的建立与输出
4.1.1建立基于邻接矩阵的无向图中
voidCreateGraph(MGraph*G)
{inti,j,k;
VertexTypev1,v2;
printf("
\n输入无向图的顶点个数,边个数(中间用逗号隔开):
"
);
scanf("
%d,%d"
&
(*G).vexnum,&
(*G).arcnum);
输入%d个顶点的名字:
(*G).vexnum);
for(i=0;
i<
(*G).vexnum;
i++)/*输入顶点向量*/
{scanf("
%s"
(*G).vexs[i]);
}
\n顶点数组:
\n"
G->
vexnum;
i++)/*输出顶点向量*/
puts(G->
vexs[i]);
i++)/*邻接矩阵初始化*/
for(j=0;
j<
j++)
(*G).arcs[i][j].adj=0;
请输入无向图中的%d条弧arcs(vivj):
(*G).arcnum);
for(k=0;
k<
(*G).arcnum;
k++)/*输入无权图的边*/
%s%s"
v1,v2);
i=LocateVex(*G,v1);
j=LocateVex(*G,v2);
(*G).arcs[i][j].adj=1;
(*G).arcs[j][i]=(*G).arcs[i][j];
}
二维数组表示邻接矩阵作图的存储结构,其中vexnum为图中顶点数,查找每个顶点的邻接点所需时间为O(n2)。
CreateGraph函数是创建一个图的初始化函数,图需要存储的信息有:
顶点和边,本算法所用的邻接矩阵是表示顶点之间相邻关系的二维数组矩阵,用于存储用户输入的顶点和边信息。
其中LocateVex是表示顶点在顶点向量中的定位的函数,其算法为:
intLocateVex(MGraphG,VertexTypev)
{inti;
G.vexnum;
i++)
if(strcmp(v,G.vexs[i])==0)break;
returni;
}
4.1.2邻接矩阵方式输出无向图
voidPrintGraph(MGraphG)
{inti,j;
\n图的邻接矩阵为:
i<
i++)
{printf("
%10s"
G.vexs[i]);
j<
j++)
%4d"
G.arcs[i][j].adj);
PrintGraph是一个简单的邻接矩阵输出矩阵,运用到二维数组、for循环等知识,其算法复杂度为O(n2)。
4.2遍历搜索算法设计
4.2.1深度优先搜索((DepthFirstSearch)
voidDfs(MGraphG,intv)
{intw;
visited[v]=TRUE;
G.vexs[v]);
for(w=FirstAdjVex(G,v);
w>
=0;
w=NextAdjVex(G,v,w))
if(!
visited[w])Dfs(G,w);
voidDfsTraverse(MGraphG)
{intv;
for(v=0;
v<
v++)
visited[v]=FALSE;
for(v=0;
if(!
visited[v])Dfs(G,v);
本算法中Dfs是采用递归的方式实现的,Dfs类似于树的先根遍历,是树的先根遍历的推广。
具体算法思想为:
从图中某个顶点v出发,访问此顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至所有与v有通路的顶点都被访问到;
若此时图中还有顶点未被访问到,则另选图中未被访问的顶点作起点,重复上述过程,直到图中所有顶点都被访问到为止,本算法中Dfs是采用递归的方式实现的。
4.2.2广度优先搜索(BreadthFirstSearch)
voidBfsTraverse(MGraphG)
{intv,u,w;
LinkQueueQ;
v++)visited[v]=FALSE;
InitQueue(&
Q);
visited[v])
{visited[v]=TRUE;
EnQueue(&
Q,v);
while(!
QueueEmpty(Q))
{DeQueue(&
Q,&
u);
for(w=FirstAdjVex(G,u);
w=NextAdjVex(G,u,w))
if(!
visited[w])
{visited[w]=TRUE;
printf("
G.vexs[w]);
EnQueue(&
Q,w);
Bfstraverse函数采用队列作为中间存储介质来实现算法,BFS类似于树的层次遍历。
具体算法流程是:
从图中某个顶点v出发,在访问了v之后,依次访问v的各个未曾访问过的邻接点(并保证先被访问的顶点的邻接点“要先于”后被访问的顶点的邻接点被访问),直至图中所有已被访问的顶点的邻接点都被访问到。
若此时图中还有未被访问的顶点,则任选其中之一作为起点,重新开始上述过程,直至图中所有顶点都被访问到。
5.程序实现及测试
5.1程序测试数据
输入顶点个数和边的个数:
7,5
输入每个顶点的名字:
1234567
程序输出所有顶点构成的一维数组:
输入五条边:
<
34>
17>
64>
35>
16>
输出的邻接矩阵应为:
0000011
0000000
0001100
0010010
0010000
1001000
1000000
以第一个节点为初始访问节点的DFS和BFS结果应分别为:
1643572,1674352
5.2调试过程及分析
在调试过程中,程序中出现了许多的错误,有错误的调用、一些变量没有定义、等等。
不断的对程序进行调试以得到最好的结果,程序中特别要注意的是类的对象作为作为参数时要注意如何去调用它,使程序有一个令人满意的结果,具体的调试是在上机过程中进行的,在编写程序的过程中主要有如下错误:
①、在编写程序的过程出现了一些函数名、变量的大小写不统一的错误,导致程序在运行的过程中出现函数名、变量没有被定义等问题;
②、在编写程序的过程中数组的大小写没有被确定;
③、在编写程序的过程中一些变量没有被定义,导致程序出错;
④、函数的返回类型要确定,是void还是其他类型要十分注意;
⑤、在编程的过程中,函数里一些控制语句的嵌套使用,括号要引起注意,程序设计中有一些括号漏了或者多打了,导致括号不配套;
(程序源代码及运行结果见附件)
6.设计体会
6.1不足之处
①、用邻接矩阵存储的图中大量的数据冗余。
对于较大的图,其存储量消耗及遍历时间复杂度的劣势均会体现出来,可以使用邻接表作为补足。
②、该程序适用的图的种类有限。
目前改程序只能用于对无向图的处理,那么对于有向图,其遍历优先级的判定的条件会发生一些变化,而且在图的初始化上也会发生变化。
可以在对初始化和遍历进行重构,封装出一个能适用于有向和无向图的遍历方法。
③、人机交互界面有待提升。
6.2课程设计感悟
用邻接矩阵作为图的数据存储结构很好地解决了图的结构难点,若借助于邻接矩阵容易判定任意两个顶点之间是否有边(或弧)相连,并容易求得各个顶点的度。
通过本次算法设计,从两种不同的重要的图遍历算法去理解了图的存储方式和图的具体操作。
并学会如何将已学过的数据结构形式灵活运用到有待解决的问题中去。
并且发现,数据结构的设计与使用不应该注重于形式,而是特定的数据结构所具有的特殊的性质,利用这些特殊的性质来帮助我们编程实现具体的问题。
这次课程设计,对我的逻辑思维能力是一个很大的锻炼,还加强了我的系统思考问题的能力,在编程方面,我开始从整体的角度来考虑问题了,而不再像以前一样的,胡乱动手。
也就是因为先前的这种编程习惯,使得我在课程设计过程中浪费了不少的时间,尝到了教训。
结束语:
通过这近一个星期的数据结构课程设计实践,我学到了很多东西。
本次课程设计对我来说正是一个提高自己能力的机会,我好好的抓住机会,努力做好每一步,完善每一步。
在今后的算法设计与编程过程中,应试着多用面向对象的角度入手,从数据结构的定义出发,进而定义出所需要的方法,完成设计与实现。
参考文献:
[1]闫玉宝,徐守坤著.数据结构.北京,清华大学出版社,2008,3.
[2]M.H.Alsuwaiyel著.方世昌等译.朱洪审校.算法设计技巧与分析.北京,电子工业出版社,2004,8.
[3]FredBuckley,MartyLewinter著.李慧霸,王凤芹译.图论简明教程.北京,清华大学出版社,2005,1.
[4]严蔚敏,吴伟民.数据结构(c语言版).北京:
清华大学出版社,2009
[5]谭浩强,等.c语言程序设计教程.北京:
高等教育出版社,2007
附件1
源程序:
/*采用邻接矩阵完成无向图的“建立、深度遍历、广度遍历”操作*/
#include"
stdio.h"
string.h"
#defineTRUE1
#defineFALSE0
#defineOVERFLOW-2
#defineOK1
#defineERROR0
typedefintStatus;
#defineINFINITYINT_MAX/*最大值“无穷”*/
#defineMAX_VERTEX_NUM20/*最大顶点个数*/
typedefintBoolean;
typedefcharVertexType[20];
typedefintVRType;
/**************以下为队列的操作************/
/****队列的类型定义****/
/****初始化队列****/
StatusInitQueue(LinkQueue*Q)
{(*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));
(*Q).front)exit(OVERFLOW);
(*Q).front->
next=NULL;
returnOK;
/****判断队列是否为空****/
StatusQueueEmpty(LinkQueueQ)
{if(Q.front==Q.rear)
returnTRUE;
else
returnFALSE;
/****入队列****/
StatusEnQueue(LinkQueue*Q,QElemTypee)
{QueuePtrp;
p=(QueuePtr)malloc(sizeof(QNode));
p)exit(OVERFLOW);
p->
data=e;
(*Q).rear->
next=p;
(*Q).rear=p;
/****出队列****/
StatusDeQueue(LinkQueue*Q,QElemType*e)
if((*Q).front==(*Q).rear)returnERROR;
p=(*Q).front->
next;
*e=p->
data;
next=p->
if((*Q).rear==p)(*Q).rear=(*Q).front;
free(p);
/**************以下为图的操作************/
/*图的类型定义*/
/*图中有1/0表示是否有边,网中表示边上的权值*/
/*顶点向量*/
/*邻接矩阵*/
intvexnum,arcnum;
/*图中当前顶点数和边数*/
}MGraph;
/*建立无向图的邻接矩阵*/
\n输入图的顶点个数,边个数(中间用逗号隔开):