图的遍历.docx
- 文档编号:12612487
- 上传时间:2023-04-20
- 格式:DOCX
- 页数:22
- 大小:185.26KB
图的遍历.docx
《图的遍历.docx》由会员分享,可在线阅读,更多相关《图的遍历.docx(22页珍藏版)》请在冰豆网上搜索。
图的遍历
数据结构课程设计报告
图遍历的演示
姓名:
贾西洋
学号:
201101050909
院系:
信息学院
班级:
信管11-1
二〇一三年六月
图遍历的演示
题目:
很多涉及图上操作的算法都是以图的遍历操作为基础的。
试写一个程序,演示在连通的无向图上访问全部结点的操作。
一、需求分析
1、以邻接多重表为存储结构;
2、实现连通和非连通的无向图的深度优先和广度优先遍历;
3、要求利用栈实现无向图的深度优先遍历;
4、以用户指定的结点为起点,分别输出每种遍历下的结点访问序列和生成树的边集;
二、概要设计
1、设定图的抽象数据类型:
ADTGraph{
数据对象V:
V是具有相同特性的数据元素的集合,称为点集.
数据关系R:
R={VR}
VR={(v,w)|v,w属于V,(v,w)表示v和w之间存在的路径}
基本操作P:
CreatGraph(&G,V,VR)
初始条件:
V是图的顶点集,VR是图中弧的集合.
操作结果:
按V和VR是定义构造图G.
DestroyGraph(&G)
初始条件:
图G存在
操作结果:
销毁图G
LocateVex(G,u)
初始条件:
图G存在,u和G中顶点有相同的特征
操作结果:
若图G中存在顶点u,则返回该顶点在图中的位置;否则返回其他信息
GetVex(G,v)
初始条件:
图G存在,v是G中顶点
操作结果:
返回v的值
FirstAjvex(G,v)
初始条件:
图G存在,v是G中顶点
操作结果:
返回v的第一个邻接顶点,若顶在图中没有邻接顶点,则返回为空
NextAjvex(G,v,w)
初始条件:
图G存在,v是G中顶点,w是v的邻接顶点
操作结果:
返回v的下一个邻接顶点,若w是v的最后一个邻接顶点,则返回空
DeleteVexx(&G,v)
初始条件:
图G存在,v是G中顶点
操作结果:
删除顶点v已经其相关的弧
DFSTraverse(G,visit())
初始条件:
图G存在,visit的顶点的应用函数
操作结果:
对图进行深度优先遍历,在遍历过程中对每个结点调用visit函数一次,一旦visit失败,则操作失败
BFSTraverse(G,visit())
初始条件:
图G存在,visit的顶点的应用函数
操作结果:
对图进行广度优先遍历,在遍历过程中对每个结点调用visit函数一次,一旦visit失败,则操作失败
}ADTGraph
2、设定队列的抽象数据类型:
ADTQueue{
数据对象:
D={ai|ai属于Elemset,i=1,2….,n,n>=0}
数据关系:
R1={
约定ai为端为队列头,an为队列尾
基本操作:
InitQueue(&Q)
操作结果:
构造一个空队列Q
DestryoQueue(&Q)
初始条件:
队列Q已存在。
操作结果:
队列Q被销毁,不再存在。
EnQueue(&Q,e)
初始条件:
队列Q已经存在
操作结果:
插入元素e为Q的新的队尾元素
DeQueue(&Q,&E)
初始条件:
Q为非空队列
操作结果:
删除Q的队尾元素,并用e返回其值
QueueEmpty(Q)
初始条件:
队列已经存在
操作结果:
若队列为空,则返回TRUE,否则返回FLASE
}ADTQueue
3、本程序包含四个模块:
1)主程序模块
voidmain()
{
手动构造一个图;
进行深度优先遍历图;
进行广度优先遍历图;
};
2)手动构造一个图-自己输入图的顶点和边生成一个图;
3)进行深度优先遍历图-打出遍历的结点序列和边集;
4)进行广度优先遍历图-打出遍历的结点序列和边集;
三、详细设计
1、顶点,边和图类型
#defineMAX_INFO10/*相关信息字符串的最大长度+1*/
#defineMAX_VERTEX_NUM20/*图中顶点数的最大值*/
intvisited[MAX_VERTEX_NUM];/*全局变量,访问标志数组*/
typedefcharInfoType;/*相关信息类型*/
typedefcharVertexType;/*字符类型*/
typedefenum{unvisited,visited}VisitIf;
typedefstructEBox/*边结点类型*/
{
intmark;/*访问标记*/
intivex,jvex;/*该边依附的两个顶点位置*/
structEBox*ilink,*jlink;/*分别指向依附这两个顶点的下一条边*/
}EBox;
typedefstructVexBox/*顶点结点类型*/
{
chardata[MAX_LEN];
EBox*fistedge;/*指向第一条依附该顶点的边*/
}VexBox;
typedefstruct
{
VexBoxlist[MAX_VERTEX_NUM];
intvexnum,edgenum;/*无向图当前顶点数和边数*/
}AMLGraph;
图的基本操作如下:
intLocateVex(AMLGraphG,VertexTypeu);
//查G和u有相同特征的顶点,若存在则返回该顶点在无向图中位置;否则返回-1。
VertexType&GetVex(AMLGraphG,intv);
//以v返回邻接多重表中序号为i的顶点。
intFirstAdjVex(AMLGraphG,VertexTypev);
//返回v的第一个邻接顶点的序号。
若顶点在G中没有邻接顶点,则返回-1。
intNextAdjVex(AMLGraphG,VertexTypev,VertexTypew);
//返回v的(相对于w的)下一个邻接顶点的序号若w是v的最后一个邻接点,则返回-1。
voidCreateGraph(AMLGraph&G);
//采用邻接多重表存储结构,构造无向图G。
StatusDeleteArc(AMLGraph&G,VertexTypev,VertexTypew);
//在G中删除边
StatusDeleteVex(AMLGraph&G,VertexTypev);
//在G中删除顶点v及其相关的边。
voidDestroyGraph(AMLGraph&G);
//销毁一个图
voidDisplay(AMLGraphG);
//输出无向图的邻接多重表G。
voidDFSTraverse(AMLGraphG,VertexTypestart,int(*visit)(VertexType));
//从start顶点起,(利用栈非递归)深度优先遍历图G。
voidBFSTraverse(AMLGraphG,VertexTypestart,int(*Visit)(VertexType));
//从start顶点起,广度优先遍历图G。
voidMarkUnvizited(AMLGraphG);//置边的访问标记为未被访问。
其中部分操作的算法如下:
voidCreateGraph(AMLGraph*p)/*创建无向图*/
{
inti,j,k;
EBox*q;
printf("\n\t\t\t请输入图的结点个数和边的个数:
");
/*输入图的结点数和边数*/
scanf("%d,%d",&p->vexnum,&p->edgenum);
for(i=1;i<=p->vexnum;i++)
{printf("\n\t\t\t请输入结点%d的名称:
",i);/*输入顶点数据信息*/
scanf("%s",p->list[i].data);
p->list[i].fistedge=NULL;/*初始化指针*/
}
for(k=0;k
{printf("\n\t\t\t请输入互相有关联的两个结点:
");
scanf("%d,%d",&i,&j);
q=(EBox*)malloc(sizeof(EBox));
q->mark=0;/*对边结点赋值*/
q->ivex=i;
q->ilink=p->list[i].fistedge;
q->jvex=j;
q->jlink=p->list[j].fistedge;
p->list[i].fistedge=p->list[j].fistedge=q;/*完成边在链头的插入*/
}
printf("\n");
}
voidDFS(AMLGraph*p,intv)
{/*对第v个顶点的深度优先遍历*/
intw;
EBox*q;
visited[v]=1;/*标记已访问结点*/
printf("%s",p->list[v].data);
for(q=p->list[v].fistedge;q!
=NULL;)
{if(q->ivex==v)
{w=q->jvex;q=q->jlink;}
else
{w=q->ivex;q=q->ilink;}
if(!
visited[w])DFS(p,w);/*对尚未访问的点调用DFS*/
}
}
voidDFSTraverse(AMLGraph*p,intn)
{/*深度优先遍历*/
intv;
printf("\n\t\t\t");
for(v=1;v<=p->vexnum;v++)
visited[v]=0;*访问标志数组初始化*/
DFS(p,n);/*对起始顶点调用DFS*/
for(v=1;v<=p->vexnum;v++)
if(!
visited[v])DFS(p,v);/*对尚未访问的顶点调用DFS*/
printf("\n");
}
2、队列类型
typedefintQelemType;
typedefstructQNode{
QElemTypedata;
structQNode*next;
}QNode,*QueuePtr;
typedefstruct{
QueuePtrfront;
QueuePtrrear;/*队头、队尾指针*/
}LinkQueue;
队列的基本操作如下:
StatusInitQueue(LinkQueue&Q);//构造一个空队列Q。
StatusDestroyQueue(LinkQueue&Q);//销毁队列Q(无论空否均可)。
StatusQueueEmpty(LinkQueueQ);//若Q为空队列,则返回1,否则返回-1。
StatusEnQueue(LinkQueue&Q,QElemTypee);//插入元素e为Q的新的队尾元素。
StatusDeQueue(LinkQueue&Q,QElemType&e);//若队列不空,删除Q的队头元素,用e返回其值,并返回1,否则返回-1。
其中部分操作的算法如下:
voidBFS(AMLGraph*p,intv)
{/*对第v个顶点进行广度优先遍历*/
intu,w;
EBox*x;
typedefstructqueue
{
intm;
structqueue*next;
}Q;/*辅助队列Q*/
Q*head,*tail,*q;
head=tail=(Q*)malloc(sizeof(Q));
tail->next=NULL;
visited[v]=1;/*标记已访问结点*/
printf("%s",p->list[v].data);
tail->m=v;/*v入队列*/
tail->next=(Q*)malloc(sizeof(Q));
tail=tail->next;
tail->next=NULL;
while(head!
=tail)
{
q=head;
head=head->next;
u=q->m;/*对头元素出队并置为u*/
free(q);
for(x=p->list[u].fistedge;x!
=NULL;)
{if(x->ivex==u){w=x->jvex;x=x->ilink;}
else{w=x->ivex;x=x->jlink;}
if(!
visited[w])
{
visited[w]=1;
printf("%s",p->list[w].data);
tail->m=w;/*w入队列*/
tail=tail->next=(Q*)malloc(sizeof(Q));
tail->next=NULL;
}/*if*/
}/*for*/
}/*while*/
}/*BFS*/
voidBFSTraverse(AMLGraph*p,intn)
{printf("\n\t\t\t");/*广度优先遍历*/
intv;
for(v=1;v<=p->vexnum;v++)
visited[v]=0;/*访问标志数组初始化*/
BFS(p,n);/*对起始顶点调用BFS*/
for(v=1;v<=p->vexnum;v++)
if(!
visited[v])BFS(p,v);
printf("\n");/*对未访问顶点调用BFS*/
}
3、主程序和其他伪码算法voidmain(){显示菜单;输入功能选择键;switch(flag){case1:
手动构造一个图;case2:
进行深度优先遍历图;case3:
进行广度优先遍历图;case4:
退出程序;}算法代码
intmain()/*主函数*/
{intx,n;
AMLGraphgraph,*p;
p=&graph;
printf("\t\t\t******图的深度和广度优先遍历*******\n");
printf("\t\t\t**\n")
while
(1)
{printf("\n");
printf("\t\t\t~~~~~~~~功能菜单~~~~~~~\n");
printf("\n");
printf("\t\t\t*********************************************\n");
printf("\t\t\t*1.创建图*\n");
printf("\t\t\t**\n");
printf("\t\t\t*2.深度优先遍历图*\n");
printf("\t\t\t**\n");
printf("\t\t\t*3.广度优先遍历图*\n");
printf("\t\t\t**\n");
printf("\t\t\t*4.退出系统*\n");
printf("\t\t\t**\n");
printf("\t\t\t*********************************************\n");
printf("\n\t\t\t请输入选择的功能编号(1-4):
");
scanf("%d",&n);
if(n<0||n>4)
{
printf("\n\n\t\t\t你输入的功能号错误,请重新输入,按Enter键继续!
!
");
getchar();
getchar();
continue;
}
switch(n)
{
case1:
CreateGraph(p);break;
case2:
{
printf("\n\t\t\t请输入起始遍历结点:
");
scanf("%d",&x);
printf("\n\t\t\t深度优先遍历结果为:
");
printf("\n");
DFSTraverse(p,x);
printf("\n");
}break;
case3:
{
printf("\n\t\t\t请输入起始遍历结点:
");
scanf("%d",&x);
printf("\n\t\t\t广度优先遍历结果为:
");
printf("\n");
BFSTraverse(p,x);
printf("\n");
}break;
case4:
printf("\n\n\t\t\t谢谢你的使用!
\n\n\n");
exit(0);
}/*switch*/
}/*while*/
return0;
}/*main*/
四、调试分析1、本程序以邻接多重表为存储结构。
这个程序涉及到图的生成和图的深度以及广度遍历,文件的保存和读取,还有栈和队列的操作,另外还有森林的生成和打印,路径的寻找。
2、本程序不仅可以进行连通无向图的遍历,还可以进行非连通图的遍历。
为了方便显示和理解,现在暂且用一个大写字母表示一个顶点。
边还可以附加信息,但为了方便操作,暂且不输入信息。
已经先把图的相关信息保存在了文本文档里,所以要测试时直接从文件导入,可以减少用手输入的麻烦,同时也可以减少输入的错误。
3、由于构造图时,后输入的边是插在先输入的边的前面。
所以在输入边时,可以按字母从大到小的顺序输入。
那么显示图的时候就可以按字母从小到大的顺序显示。
4、程序定义了一个二倍顶点长的数组存放输入的边,以便程序可以把它保存到文件里。
故耗费了一定的内存空间。
五、用户手册1、进入演示程序后即显示一个有功能选择的界面,如下:
2、选择操作1:
程序就提示分别输入无向图的顶点数,边数,边的信息,顶点和边的值:
输入完成后,返回菜单。
3、选择操作2:
系统提示输入遍历图的起始点,程序运行后,首先显示深度优先遍历的访问结点序列。
4、选择操作3:
系统提示输入遍历图的起始点,程序运行后,首先显示广度优先遍历的访问结点序列。
5、选择操作4:
退出程序。
六、测试结果
附:
源程序
#include
#include
#defineMAX_VERTEX_NUM30/*无向图最大顶点数*/
#defineMAX_LEN20/*数据最大长度*/
intvisited[MAX_VERTEX_NUM];/*全局变量,访问标志数组*/
typedefstructEBox/*边结点类型*/
{
intmark;/*访问标记*/
intivex,jvex;/*该边依附的两个顶点位置*/
structEBox*ilink,*jlink;/*分别指向依附这两个顶点的下一条边*/
}EBox;
typedefstructVexBox/*顶点结点类型*/
{
chardata[MAX_LEN];
EBox*fistedge;/*指向第一条依附该顶点的边*/
}VexBox;
typedefstruct
{
VexBoxlist[MAX_VERTEX_NUM];
intvexnum,edgenum;/*无向图当前顶点数和边数*/
}AMLGraph;
voidCreateGraph(AMLGraph*p)/*创建无向图*/
{
inti,j,k;
EBox*q;
printf("\n\t\t\t请输入图的结点个数和边的个数:
");/*输入图的结点数和边数*/
scanf("%d,%d",&p->vexnum,&p->edgenum);
for(i=1;i<=p->vexnum;i++)
{printf("\n\t\t\t请输入结点%d的名称:
",i);/*输入顶点数据信息*/
scanf("%s",p->list[i].data);
p->list[i].fistedge=NULL;/*初始化指针*/
}
for(k=0;k
{printf("\n\t\t\t请输入互相有关联的两个结点:
");
scanf("%d,%d",&i,&j);
q=(EBox*)malloc(sizeof(EBox));
q->mark=0;/*对边结点赋值*/
q->ivex=i;
q->ilink=p->list[i].fistedge;
q->jvex=j;
q->jlink=p->list[j].fistedge;
p->list[i].fistedge=p->list[j].fistedge=q;/*完成边在链头的插入*/
}
printf("\n");
}
voidDFS(AMLGraph*p,intv)
{/*对第v个顶点的深度优先遍历*/
intw;
EBox*q;
visited[v]=1;/*标记已访问结点*/
printf("%s",p->list[v].data);
for(q=p->list[v].fistedge;q!
=NULL;)
{if(q->ivex==v)
{w=q->jvex;q=q->jlink;}
else
{w=q->ivex;q=q->ilink;}
if(!
visited[w])DFS(p,w);/*对尚未访问的点调用DFS*/
}
}
voidDFSTraverse(AMLGraph*p,intn)
{/*深度优先遍历*/
intv;
printf("\n\t\t\t");
for(v=1;v<=p->vexnum;v++)
visited[v]=0;/*访问标志数组初始化*/
DFS(p,n);/*对起始顶点调用DFS*/
for(v=1;v<=p->vexnum;v++)
if(!
visited[v])DFS(p,v);/*对尚未访问的顶点调用DFS*/
printf("\n");
}
voidBFS(AMLGraph*p,intv)
{/*对第v个顶点进行广度优先遍历*/
intu,w;
EBox*x;
typedefstructqueue
{
intm;
structqueue*next;
}Q;/*辅助队列Q*/
Q*head,*tail,*q;
head=tail=(Q*)malloc(sizeof(Q));
tail->next=NULL;
visited[v]=1;/*标记已访问结点*/
printf("%s",p->list[v].d
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 遍历