数据结构课设c语言课设图的遍历的演.docx
- 文档编号:24307393
- 上传时间:2023-05-26
- 格式:DOCX
- 页数:21
- 大小:110.48KB
数据结构课设c语言课设图的遍历的演.docx
《数据结构课设c语言课设图的遍历的演.docx》由会员分享,可在线阅读,更多相关《数据结构课设c语言课设图的遍历的演.docx(21页珍藏版)》请在冰豆网上搜索。
数据结构课设c语言课设图的遍历的演
算法与数据结构课程设计
题目:
图遍历的演示
专业班级:
09级网络
******
学号:
********
指导教师:
成绩:
_______________
摘要
(1)使用键盘的操作实行各种信息的输入(包括员图的结点、结点之间的连线);并将相应结果输出等功能;
(2)建立图,规定图的结点的个数少于十个,实现图的遍历
(3)算法对于一些精心选择的典型、苛刻而带有刁难性的几组输入数据能够得出满足规格说明要求的结果;对算法实现过程中的异常情况能给出出错信息;
(4)图的遍历的方法有广度优先遍历和深度优先遍历,按照设计任务书的要求实现图的两种遍历,并且输出结果
(5)较高要求:
实现图形化操作界面。
前言
该设计要求学生本学期对数据结构的学习为背景,设计出一个简单的能够实现图的遍历的系统。
通过该题目的设计过程,可以加深理解图、图的遍历、图的广度优先遍历,图的深度优先遍历、图的创建等一系列算法的创建,进一步理解和熟练掌握课本中所学的各种数据结构,学会如何把学到的知识用于解决实际问题,培养学生的动手能力。
正文
问题描述
该课题要求熟悉图的结构和其基本操作,掌握数组的建立和使用方法,学会利用递归和非递归的方法对其进行遍历。
和树的遍历类似,图的遍历也是从某个顶点出发,沿着某条搜索路径对图中每个顶点各做一次且仅做一次访问。
它是许多图的算法的基础。
遍历常用两种方法:
深度优先搜索遍历;广度优先搜索遍历
逻辑设计
1图的创建
该课题主要是以邻接矩阵的方式存储图,并以图形的方式输出图,所以在图的创建的过程中主要是输入图中各结点的关系,比方说1号结点和2号结点之间有联系,那么就得输入(1,2),但是总得设置一个结束的条件,在这里我就以(0,0)结束,这样比较好控制。
而且初始化时得把所有邻接矩阵都初始化为0,那么当两个结点有关系时就可以设置为1.
2图的输出
图的输出主要是以printfgraph()函数实现的。
因为输出图的特殊性,结点的位置如果随机的定义,工程量太大,而且涉及到数学方面的计算,所以我就把结点初定为6个。
并且已经定好结点的位置,但是结点与结点之间的联系却没有定好,是按用户输入的情况进行连接的。
3图的深度优先遍历
当用户需要深度优先遍历时,由于公共变量visited里的值可能会受到其他的变化,所以一开始就把所有结点都定义为未访问,然后当其访问到哪个结点时再把相应的结点的visited设置为1,即已经访问。
再用visitvex函数显示该结点已访问。
再查找该结点的下一个结点,实行递归。
直到所有的结点都已经访问完。
4图的广度优先遍历
当用户需要广度优先遍历时,首先得初始化一个队列,并初始化其为一个空队列。
而且由于公共变量visited里的值可能会受到其他的变化,所以一开始就把所有结点都定义为未访问,然后当其访问到哪个结点时再把相应的结点的visited设置为1,即已经访问。
再用visitvex函数显示该结点已访问。
然后再把该结点入队。
只要队不为空。
就把队里的结点出队。
并查找下一个结点,直到所有的结点都已经访问完
5输入输出的要求
5.1输入的要求
本来可以手动输入要遍历的总结点数,但是由于结点位置如果以这种方式的话就无法确定,即使有一定的规律,而边的确定也不好把握,所以本设计中已经定好了结点的相应位置,我们只需要输入结点之间是不是有边连接就可行,并输入那条边所连接的起始点和终点。
5.2输出的要求
因为本课题要求的是演示图的遍历过程,所以我们必须在构建好邻接矩阵后要把整个图给显示出来。
而且重点要演示图的遍历,所以在图中要演示这个过程,在本设计中我是遍历一个结点要求再按一个键再遍历下一个结点,这样也不会因为遍历过程太快根本就看不到这个过程,而且我是用填充图形的方式显示这个结点,这样比较打眼。
当使用另外一种遍历方式时,我就把填充图形函数的方式的颜色更改一下。
这样就可以完成整个设计的需要。
5.3设计方案
5.3、1总体设计流程
1图的初始化
定义图并初始化图
2.建立图的邻接表
3.图的遍历
1.图的深度优先搜索
2.图的广度优先搜索
5.3、2图的遍历的模块化
1.图的存储结构;
2.图的输入;
3.BFS和DFS编码;
概要设计
2.1主函数功能模块图:
图2.1.1主函数功能模块图
主流程图
详细设计
1抽象数据类型图的定义如下:
ADTGraph{
数据对象:
D={ai|ai∈ElemSet,i=1,2,...,n,n≥0}
数据关系:
R1={
基本运算:
creatgraph(g,n):
建立一个邻接矩阵并以一个二元数组存储
BESTraverse(g):
将图以广度优先算法的思路进行遍历
printgraph(g):
将图按照自己存储的二元数组以图形的方式输出
dfstraverse(g):
将图以深度优先算法的思路进行遍历
}ADTGraph
2抽象数据类型队列的定义如下:
ADTQueue{
数据对象:
D={ai|ai∈ElemSet,i=1,2,...,n,n≥0}
数据关系:
R1={
约定其中a1端为队列头,an端为队列尾
基本操作:
initqueue(q)操作结果:
构造一个空队列。
queempty(q)初始条件:
队列q已存在。
操作结果:
若q为空队列,则返回0,否则返回1
enqueue(q,e)初始条件:
队列q已存在。
操作结果:
插入元素e为q的新的队尾元素。
dequeue(q)初始条件:
q为非空队列。
操作结果:
删除q的队头元素,并用t返回其值。
}ADTQueue
程序编码
3.1采用C语言定义相关的数据类型
3.1.1图的定义
/*定义图*/
typedefstruct{
intV[M]
intR[M][M]
intvexnum
}Graph
/*创建图*/
voidcreatgraph(Graph*g,intn)
{
inti,j,r1,r2
g
>vexnum=n
/*顶点用i表示*/
for(i=1i<=ni++)
{
g
>V[i]=i
}
/*初始化R*/
for(i=1i<=ni++)
for(j=1j<=nj++)
{
g
>R[i][j]=0
}
3.1.2队列的定义
typedefstruct{
intV[M];
intfront;
intrear;
}Queue;
3.2写出各模块的类C码算法
3.2.1Creatgraph(g,n)/*创建图函数伪代码*/
Begin//开始
n=>g->vexnum
for(i=1;i<=n;i++)/*顶点用i表示*/
theni=>g->V[i]
for(i=1;i<=n;i++)/*初始化R*/
for(j=1;j<=n;j++)
then
0=>g->R[i][j]
Scanfr1,r2
while(r1!
=0&&r2!
=0)
do1=>g->R[r1][r2]
1=>g->R[r2][r1]
scanfr1,r2
enddo
End/*算法结束*/
3.2.2BESTraverse(g)/*广度优先算法*/
begin
(Queue*)malloc(sizeof(Queue))=>Queue*q//初始化q
for(i=1;i<=g->vexnum;i++)//将所有的结点的访问标志都定为0
then0=>visited[i]
initqueue(q)
for(i=1;i<=g->vexnum;i++)
then
if(!
visited[i])/*如果尚未被访问则置访问标志为1并且输出入队*/
then
visited[i]=1;/**/
visitvex(g,g->V[i])
enqueue(q,g->V[i])
while(quempty(q)==1)
do
i=dequeue(q);//将队列中的元素出队
for(j=1;j<=g->vexnum;j++)
{
if(g->R[i][j]!
=0&&visited[j]==0)//输出i结点所有未访问的邻接点
{
visited[j]=1;
visitvex(g,j);
enqueue(q,j);
}}
endif
enddo
end/*算法结束*/
3.2.3dfstraverse(g)/*深度优先算法的伪代码*/
begin
for(i=1;i<=g->vexnum;i++)
0=>visited[i]
for(i=1;i<=g->vexnum;i++)
if(!
visited[i])
thendfs(g,i)
endif
end/*算法结束*/
3.2.4printgraph(g)/*输出图*/
begin
/*画结点*/
for(i=0;i<6;i++)
{circle(r[i][0],r[i][1],12)
outtextxy(r[i][0],r[i][1],s[i])}
/*画出各结点之间有联系的线段*/
for(i=1;i<=g->vexnum;i++)
for(j=1;j<=g->vexnum;j++)
thenif(g->R[i][j]!
=0)
thenif(i==1&&j==2)line(l[0][0],l[0][1],l[0][2],l[0][3])
elseif((i==1)&&(j==3))line(l[1][0],l[1][1],l[1][2],l[1][3])
elseif((i==2)&&(j==3))line(l[2][0],l[2][1],l[2][2],l[2][3])
elseif((i==2)&&(j==4))line(l[3][0],l[3][1],l[3][2],l[3][3])
elseif((i==2)&&(j==5))line(l[4][0],l[4][1],l[4][2],l[4][3])
elseif((i==3)&&(j==5))line(l[5][0],l[5][1],l[5][2],l[5][3])
elseif((i==3)&&(j==6))line(l[6][0],l[6][1],l[6][2],l[6][3])
elseif((i==4)&&(j==5))line(l[7][0],l[7][1],l[7][2],l[7][3])
elseif((i==5)&&(j==6))line(l[8][0],l[8][1],l[8][2],l[8][3])
elseif((i==1)&&(j==5))line(l[9][0],l[9][1],l[9][2],l[9][3])}
endif
endif
end/*算法结束*/
程序的调试与测试
1.首先用户首先看到的是运行的第一步,对用户的提示,请输入顶点数和弧数:
2.第二步,当用户输入顶点数和弧数后,界面就会有提示,请输入一定的顶点数
3.当输入顶点的数目和自己预定的数目相等的时候,程序会自动跳转到输入弧的项目,如下图所示:
4.按照规定的方法输入顶点之间的联通弧,并且输入他们之间的弧的数目,如下图所示:
5.运行的结果如下图所示:
结果分析
刚开始想用邻接表的方式去存储,可是因为邻接矩阵的存储不是太方便,而且在输入的时候也难以实现,后来就想到用邻接矩阵的方式去存储数据,就只存储有边连接的两个结点,而在输入时不知道以什么方式来结束这种输入,最后想到当两个结点为0时结束这种输入。
而在输出图时,也遇到了前所未有的难题,就是我的图形已经是确定了的结点,那么连接它的边所画的直线也就确定了,可是我就是无法将其与程序连接,结果我把for(i=1j=1;i<=g->vexnum&&j<=g->vexnum&&g->R[i][j]!
=0;i++,j++)放在一起作为条件,结果根本就不能识别因为在主对角线上的数都是0,所以整个函数根本没有进入内层循环,后来才想到,原来i++,那么j++,那么他们就是主对角线上的数,后来改为双重循环for(i=1;i<=g->vexnum;i++)
for(j=1;j<=g->vexnum;j++)再写条件if(g->R[i][j]!
=0)然后就可以读取数据,并根据自己输入的边的要求连接好。
还有就是在遍历的时候也碰到不少的问题,就是有一些结点遍历了就是无法改变填充颜色,后来才知道原来是设置的颜色问题。
还有可能是自己设置的一些变量对其产生一些影响,使其不能显示。
还有这次的广度遍历是我遇到的最大问题,它刚开始一直就只能以1,2,3,4,5,6,的形式输出,后来我发现了它每遍历一个结点,它并不是把它的所有邻接结点全部找到并输出,而是再继续找它的第一个结点的邻接结点,有点类似于深度遍历。
所以我就设置了一个队列把第一个结点输出后就出队,然后再以它为一维,遍历邻接矩阵的一行,这样等于就是找到了它的所有邻接点了。
这样也就实现了深度遍历。
使用说明
当用户进入界面时就会有提示,请输入顶点数和弧数,按照自己的要求输入顶点的数目和弧的数目例如顶点数目为6个,弧的数目为5个,然后点下回车键进行下一步的编译
1.要求用户输入顶点的名称,可按照自己的想法给顶点编号,例如a,b,c,d,e,f每输入一个顶点时要按一下回车键,以确保输入的编号被正确读入和以免出现误差,当输入的顶点数目和自己的第一步输入的数目相等时就会进行下一步的操作
2.然后就有提示,要求输入几条弧,我们输入的是五条弧,就按照要求输入顶点之间的联通关系和弧的数目,例如ab1、ac1、be1、ef1、cd1,然后按回车键近行下一步的操作
3.程序会自动进行广度优先遍历和深度优先遍历,然后输出结果:
广度优先遍历:
abefcd
深度优先遍历:
abcedf
4.按任何键结束程序的运行
设计总结
转眼,为期两周的《数据结构》课程设计即将结束了。
我的题目是:
图遍历的演示,这两周课程设计中,通过该题目的设计过程,自己的C语言知识和数据结构知识得到了巩固,编程能力也有了一定的提高,我加深了对图数据结构及队列的逻辑结构,存储结构及图的深度优先和广度优先遍历过程的理解,对图数据结构上基本运算的实现有所掌握,对课本中所学的各种数据结构进一步理解和掌握,学会了如何把学到的知识用于解决实际问题,锻炼了自己动手的能力。
总结起来,自己主要有以下几点体会:
1.必须牢固掌握基础知识。
由于C语言是大一所学知识,有所遗忘,且未掌握好这学期所学的《数据结构》这门课,所以在实习之初感到棘手。
不知如何下手,但在后来的实习过程中自己通过看书和课外资料,并请教其他同学,慢慢地对C语言和数据结构知识有所熟悉。
这时才逐渐有了思路。
所以,这次实习之后,我告诫自己:
今后一定要牢固掌握好专业基础知识。
2.必须培养严谨的科学态度。
自己在编程时经常因为一些类似于“少了分号”的小错误而导致错误,不够认真细致,这给自己带来了许多麻烦。
编程是一件十分严谨的事情,容不得马虎。
所以在今后自己一定要培养严谨的科学态度。
我想这不仅是对于程序设计,做任何事都应如此。
3.这次课程设计也让我充分认识到《数据结构》这门课的重要性。
它给我们一个思想和大纲,让我们在编程时容易找到思路,不至于无章可循。
同时它也有广泛的实际应用。
在课程设计时遇到了很多的问题,在老师的帮助,和对各种资料的查阅中,将问题解决,培养了我自主动手,独立研究的能力,为今后在学习工作中能更好的发展打下了坚实的基础。
两周的课程设计很短暂,但其间的内容是很充实的,在其中我学习到了很多平时书本中无法学到的东西,积累了经验,锻炼了自己分析问题,解决问题的能力,并学会了如何将所学的各课知识融会,组织,来配合学习,两周中我收益很大,学到很多。
参考文献
1.严蔚敏,吴伟民,《数据结构(C语言版)》,北京:
清华大学出版社,2005
2.严蔚敏,吴伟民,《数据结构题集(C语言版)》,北京:
清华大学出版社,2003
3.杨旭《C语言程序设计案例教程》人民邮电出版社2005
4.谭浩强,《C语言程序设计》,北京:
清华大学出版社,2005
六、附件
源程序清单:
#include
//#include
#defineINFINITY32767
#defineMAX_VEX20//最大顶点个数
#defineQUEUE_SIZE(MAX_VEX+1)//队列长度
usingnamespacestd;
bool*visited;//访问标志数组
//图的邻接矩阵存储结构
typedefstruct{
char*vexs;//顶点向量
intarcs[MAX_VEX][MAX_VEX];//邻接矩阵
intvexnum,arcnum;//图的当前顶点数和弧数
}Graph;
//队列类
classQueue{
public:
voidInitQueue(){
base=(int*)malloc(QUEUE_SIZE*sizeof(int));
front=rear=0;
}
voidEnQueue(inte){
base[rear]=e;
rear=(rear+1)%QUEUE_SIZE;
}
voidDeQueue(int&e){
e=base[front];
front=(front+1)%QUEUE_SIZE;
}
public:
int*base;
intfront;
intrear;
};
//图G中查找元素c的位置
intLocate(GraphG,charc){
for(inti=0;i if(G.vexs[i]==c)returni; return-1; } //创建无向网 voidCreateUDN(Graph&G){ inti,j,w,s1,s2; chara,b,temp; printf("输入顶点数和弧数: "); scanf("%d%d",&G.vexnum,&G.arcnum); temp=getchar();//接收回车 G.vexs=(char*)malloc(G.vexnum*sizeof(char));//分配顶点数目 printf("输入%d个顶点.\n",G.vexnum); for(i=0;i printf("输入顶点%d: ",i); scanf("%c",&G.vexs[i]); temp=getchar();//接收回车 } for(i=0;i for(j=0;j G.arcs[i][j]=INFINITY; printf("输入%d条弧.\n",G.arcnum); for(i=0;i printf("输入弧%d: ",i); scanf("%c%c%d",&a,&b,&w);//输入一条边依附的顶点和权值 temp=getchar();//接收回车 s1=Locate(G,a); s2=Locate(G,b); G.arcs[s1][s2]=G.arcs[s2][s1]=w; } } //图G中顶点k的第一个邻接顶点 intFirstVex(GraphG,intk){ if(k>=0&&k for(inti=0;i if(G.arcs[k][i]! =INFINITY)returni; } return-1; } //图G中顶点i的第j个邻接顶点的下一个邻接顶点 intNextVex(GraphG,inti,intj){ if(i>=0&&i for(intk=j+1;k if(G.arcs[i][k]! =INFINITY)returnk; } return-1; } //深度优先遍历 voidDFS(GraphG,intk){ inti; if(k==-1){//第一次执行DFS时,k为-1 for(i=0;i if(! visited[i])DFS(G,i);//对尚未访问的顶点调用DFS } else{ visited[k]=true; printf("%c",G.vexs[k]);//访问第k个顶点 for(i=FirstVex(G,k);i>=0;i=NextVex(G,k,i)) if(! visited[i])DFS(G,i);//对k的尚未访问的邻接顶点i递归调用DFS } } //广度优先遍历 voidBFS(GraphG){ intk; QueueQ;//辅助队列Q Q.InitQueue(); for(inti=0;i if(! visited[i]){//i尚未访问 visited[i]=true; printf("%c",G.vexs[i]); Q.EnQueue(i);//i入列 while(Q.front! =Q.rear){ Q.DeQueue(k);//队头元素出列并置为k for(intw=FirstVex(G,k);w>=0;w=NextVex(G,k,w)) if(! visited[w]){//w为k的尚未访问的邻接顶点 visited[w]=true; printf("%c",G.vexs[w]); Q.EnQueue(w); } } } } //主函数 voidmain(){ inti; GraphG; CreateUDN(G); visited=(bool*)malloc(G.vexnum*sizeof(bool)); printf("\n广度优先遍历: "); for(i=0;i visited[i]=false; DFS(G,-1); printf("\n深度优先遍历: "); for(i=0;i visited[i]=false; BFS(G); printf("\n程序结束.\n"); }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 语言 课设图 遍历