1、 数据结构课程设计报告设计题目图的遍历演示学生姓名XXX学生班级XXXXX学生学号XXXXXX指导教师XXXXX完成时间 2015 年 12 月26 日1.1问题描述 从图中某个顶点出发访问图中所有顶点,且使得每一顶点仅被访问一次,这个过程称为图的遍历。图的遍历是从图中某个顶点出发,沿着某条搜索路径对图中其余每个顶点进行访问, 并且使图中的每个顶点仅被访问一次的过程。 图的遍历是图运算中最重要的运算,也是图的基本运算之一,图的许多运算都是以遍历为基础的。试编写一个程序,完成对图的遍历。1.2基本要求 1以邻接矩阵为存储结构,实现无向图的深度优先遍历和广度优先遍历。 2分别输出每种遍历下的结点访
2、问序列.从图中某个顶点出发,沿着某条搜索路径对图中每个顶点各做一次且仅做一次访问。它是许多图的算法的基础。图的遍历介绍 基本概念 图的遍历: 图中某个顶点出发访问图中所有顶点,且使得每一顶点仅被访问一次,这个过程称为图的遍历。图的遍历是从图中某个顶点出发,沿着某条搜索路径对图中其余每个顶点进行访问, 并且使图中的每个顶点仅被访问一次的过程。 图的遍历是图运算中最重要的运算,也是图的基本运算之一,图的许多运算都是以遍历为基础的。 1.3.2、 分类 按照搜索途径的不同,图的遍历可分为:深度优先遍历(Depth-First Traverse)和广度优先遍历(Breadth-First Traver
3、se)两大类。深度优先遍历和广度优先遍历是最为重要的两种遍历图的方法。 (1)深度优先遍历 (Depth-First Traverse) 特点:尽可能先对纵深方向的顶点进行访问 深度优先遍历的递归定义 假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,
4、直至图中所有顶点均已被访问为止。图的深度优先遍历类似于树的前序遍历。采用的搜索方法的特点是尽可能先对纵深方向进行搜索。这种搜索方法称为深度优先搜索(Depth-First Search)。相应地,用此方法遍历图就很自然地称之为图的深度优先遍历。 . 深度优先搜索的过程 a 基本思想: 首先访问图中某一个指定的出发点Vi; 然后任选一个与顶点Vi相邻的未被访问过的顶点Vj; 以Vj为新的出发点继续进行深度优先搜索,直至图中所有顶点均被访问过。 b具体过程: 设x是当前被访问顶点,在对x做过访问标记后,选择一条从x出发的未检测过的边(x,y)。若发现顶点y已访问过,则重新选择另一条从x出发的未检测
5、过的边,否则沿边(x,y)到达未曾访问过的y,对y访问并将其标记为已访问过;然后从y开始搜索,直到搜索完从y出发的所有路径,即访问完所有从y出发可达的顶点之后,才回溯到顶点x,并且再选择一条从x出发的未检测过的边。上述过程直至从x出发的所有边都已检测过为止。此时,若x不是源点,则回溯到在x之前被访问过的顶点;否则图中所有和源点有路径相通的顶点(即从源点可达的所有顶点)都已被访问过,若图G是连通图,则遍历过程结束,否则继续选择一个尚未被访问的顶点作为新源点,进行新的搜索过程。(2)广度优先遍历(Breadth-First Traverse): 特点:尽可能先从指定的出发点,横向地访问图中各个顶点
6、 广度优先遍历的定义 在访问了起始点之后,首先依次访问起始点的各个邻接点,然后依次访问那些顶点中未被访问过的邻接点.依此类推,直到所有被访问到的顶点的邻接点都被访问过为止. 广度优先搜索的过程a算法基本思想: 首先访问图中某一指定的出发点Vi; 然后依次访问Vi的所有接点Vi1,Vi2Vit; 再次访问Vi1,Vi2,Vit的邻接点中未经访问过的顶点,依此类推,直到图中所有顶点均被访问为止。b具体过程: 从广度优先搜索遍历方法可知,先被访问的顶点的邻接点也被访问,即假设顶点V在W之前被访问,那么顶点V的所有未经访问的邻接点也在顶点W的所有未经访问的邻接点之前被访问。这样可以在广度优先遍历的算
7、法中设置一个队列结构,用以保存已访问过的顶点的序号,访问该顶点的所有未经访问的顶点。 广度优先搜索是一种分层的搜索过程,每向前走一步可能访问一批顶点,不像深度优先搜索那样会出现回退的现象。因此它不是个递归的过程。为了实现逐层访问,算法中使用了一个队列以记忆正在访问的这一层和上一层的顶点,以便于向下一层访问。为了避免重复访问,需要一个辅助函数visitvex给被访问过的顶点加标记。 2.概要设计2.1算法说明邻接矩阵作为存储结构的程序示例#includestdio.h#includestdlib.h#define MaxVertexNum 100 /定义最大顶点数typedef struct c
8、har vexsMaxVertexNum; /顶点表 int edgesMaxVertexNumMaxVertexNum; /邻接矩阵,可看作边表 int n,e; /图中的顶点数n和边数eMGraph; /用邻接矩阵表示的图的类型/=建立邻接矩阵=void CreatMGraph(MGraph *G) int i,j,k; char a; printf(Input VertexNum(n) and EdgesNum(e): ); scanf(%d,%d,&G-n,&G-e); /输入顶点数和边数 scanf(%c,&a); printf(Input Vertex string:); for(
9、i=0;in;i+) scanf(%c,&a); G-vexsi=a; /读入顶点信息,建立顶点表 for(i=0;in;i+)for(j=0;jn;j+) G-edgesij=0; /初始化邻接矩阵 printf(Input edges,Creat Adjacency Matrixn); for(k=0;ke;k+) /读入e条边,建立邻接矩阵 scanf(%d%d,&i,&j); /输入边(Vi,Vj)的顶点序号 G-edgesij=1; G-edgesji=1; /若为无向图,矩阵为对称矩阵;若建立有向图,去掉该条语句 /=定义标志向量,为全局变量=typedef enumFALSE,T
10、RUE Boolean;Boolean visitedMaxVertexNum;/=DFS:深度优先遍历的递归算法=void DFSM(MGraph *G,int i) /以Vi为出发点对邻接矩阵表示的图G进行DFS搜索,邻接矩阵是0,1矩阵 int j; printf(%c,G-vexsi); /访问顶点Vi visitedi=TRUE; /置已访问标志 for(j=0;jn;j+) /依次搜索Vi的邻接点if(G-edgesij=1 & ! visitedj) DFSM(G,j); /(Vi,Vj)E,且Vj未访问过,故Vj为新出发点void DFS(MGraph *G) int i; f
11、or(i=0;in;i+)visitedi=FALSE; /标志向量初始化 for(i=0;in;i+)if(!visitedi) /Vi未访问过 DFSM(G,i); /以Vi为源点开始DFS搜索/=BFS:广度优先遍历=void BFS(MGraph *G,int k) /以Vk为源点对用邻接矩阵表示的图G进行广度优先搜索 int i,j,f=0,r=0; int cqMaxVertexNum; /定义队列 for(i=0;in;i+)visitedi=FALSE; /标志向量初始化 for(i=0;in;i+)cqi=-1; /队列初始化 printf(%c,G-vexsk); /访问源
12、点Vk visitedk=TRUE; cqr=k; /Vk已访问,将其入队。注意,实际上是将其序号入队 while(cqf!=-1) /队非空则执行 i=cqf; f=f+1; /Vf出队 for(j=0;jn;j+) /依次Vi的邻接点Vj if(G-edgesij=1 & !visitedj) /Vj未访问 printf(%c,G-vexsj); /访问Vj visitedj=TRUE; r=r+1; cqr=j; /访问过Vj入队 /=main=void main() int i; MGraph *G; G=(MGraph *)malloc(sizeof(MGraph); /为图G申请内
13、存空间 CreatMGraph(G); /建立邻接矩阵 printf(Print Graph DFS: ); DFS(G); /深度优先遍历 printf(n); printf(Print Graph BFS: ); BFS(G,3); /以序号为3的顶点开始广度优先遍历 printf(n);执行顺序:V6V4V5V7V2V3V1V0Vo图G的示例Input VertexNum(n) and EdgesNum(e): 8,9Input Vertex string: 01234567Input edges,Creat Adjacency Matrix0 10 21 31 42 52 63 74
14、75 6Print Graph DFS: 01374256Print Graph BFS: 317042561 邻接链表作为存储结构程序示例#includestdio.h#includestdlib.h#define MaxVertexNum 50 /定义最大顶点数typedef struct node /边表结点 int adjvex; /邻接点域 struct node *next; /链域EdgeNode;typedef struct vnode /顶点表结点 char vertex; /顶点域 EdgeNode *firstedge; /边表头指针VertexNode;typedef
15、VertexNode AdjListMaxVertexNum; /AdjList是邻接表类型typedef struct AdjList adjlist; /邻接表 int n,e; /图中当前顶点数和边数 ALGraph; /图类型/=建立图的邻接表=void CreatALGraph(ALGraph *G) int i,j,k; char a; EdgeNode *s; /定义边表结点 printf(Input VertexNum(n) and EdgesNum(e): ); scanf(%d,%d,&G-n,&G-e); /读入顶点数和边数 scanf(%c,&a); printf(In
16、put Vertex string:); for(i=0;in;i+) /建立边表 scanf(%c,&a);G-adjlisti.vertex=a; /读入顶点信息G-adjlisti.firstedge=NULL; /边表置为空表 printf(Input edges,Creat Adjacency Listn); for(k=0;ke;k+) /建立边表 scanf(%d%d,&i,&j); /读入边(Vi,Vj)的顶点对序号s=(EdgeNode *)malloc(sizeof(EdgeNode); /生成边表结点s-adjvex=j; /邻接点序号为js-next=G-adjlist
17、i.firstedge;G-adjlisti.firstedge=s; /将新结点*S插入顶点Vi的边表头部s=(EdgeNode *)malloc(sizeof(EdgeNode); s-adjvex=i; /邻接点序号为is-next=G-adjlistj.firstedge; G-adjlistj.firstedge=s; /将新结点*S插入顶点Vj的边表头部 /=定义标志向量,为全局变量=typedef enumFALSE,TRUE Boolean;Boolean visitedMaxVertexNum;/=DFS:深度优先遍历的递归算法=void DFSM(ALGraph *G,in
18、t i) /以Vi为出发点对邻接链表表示的图G进行DFS搜索 EdgeNode *p; printf(%c,G-adjlisti.vertex); /访问顶点Vi visitedi=TRUE; /标记Vi已访问 p=G-adjlisti.firstedge; /取Vi边表的头指针 while(p) /依次搜索Vi的邻接点Vj,这里j=p-adjvexif(! visitedp-adjvex) /若Vj尚未被访问 DFSM(G,p-adjvex); /则以Vj为出发点向纵深搜索p=p-next; /找Vi的下一个邻接点 void DFS(ALGraph *G) int i; for(i=0;in
19、i+)visitedi=FALSE; /标志向量初始化 for(i=0;in;i+)if(!visitedi) /Vi未访问过 DFSM(G,i); /以Vi为源点开始DFS搜索/=BFS:广度优先遍历=void BFS(ALGraph *G,int k) /以Vk为源点对用邻接链表表示的图G进行广度优先搜索 int i,f=0,r=0; EdgeNode *p; int cqMaxVertexNum; /定义FIFO队列 for(i=0;in;i+)visitedi=FALSE; /标志向量初始化 for(i=0;in;i+)cqi=-1; /初始化标志向量 printf(%c,G-adj
20、listk.vertex); /访问源点Vk visitedk=TRUE; cqr=k; /Vk已访问,将其入队。注意,实际上是将其序号入队 while(cqf!=-1) 队列非空则执行i=cqf; f=f+1; /Vi出队p=G-adjlisti.firstedge; /取Vi的边表头指针while(p) /依次搜索Vi的邻接点Vj(令p-adjvex=j) if(!visitedp-adjvex) /若Vj未访问过printf(%c,G-adjlistp-adjvex.vertex); /访问Vjvisitedp-adjvex=TRUE;r=r+1; cqr=p-adjvex; /访问过的
21、Vj入队 p=p-next; /找Vi的下一个邻接点 /endwhile/=主函数=void main() int i; ALGraph *G; G=(ALGraph *)malloc(sizeof(ALGraph); CreatALGraph(G); printf(Print Graph DFS: ); DFS(G); printf(n); printf(Print Graph BFS: ); BFS(G,3); printf(n);执行顺序:Input VertexNum(n) and EdgesNum(e): 8,9Input Vertex string: 01234567V6V4V5V
22、7V2V3V1V0Vo图G的示例Input edges,Creat Adjacency List0 10 21 31 42 52 63 74 75 6Print Graph DFS: 02651473Print Graph BFS: 37140265一、 修改后的代码1邻接矩阵作为存储结构的程序#includestdio.h#includestdlib.h#define MaxVertexNum 100 /定义最大顶点数typedef struct char vexsMaxVertexNum; /顶点表 int edgesMaxVertexNumMaxVertexNum; /邻接矩阵,可看作边
23、表 int n,e; /图中的顶点数n和边数eMGraph; /用邻接矩阵表示的图的类型/=建立邻接矩阵=void CreatMGraph(MGraph *G) int i,j,k; char a; printf(Input VertexNum(n) and EdgesNum(e): ); scanf(%d,%d,&G-n,&G-e); /输入顶点数和边数 scanf(%c,&a); printf(Input Vertex string:); for(i=0;in;i+) scanf(%c,&a); G-vexsi=a; /读入顶点信息,建立顶点表 for(i=0;in;i+)for(j=0;
24、jn;j+) G-edgesij=0; /初始化邻接矩阵 printf(Input edges,Creat Adjacency Matrixn); for(k=0;ke;k+) /读入e条边,建立邻接矩阵 scanf(%d%d,&i,&j); /输入边(Vi,Vj)的顶点序号 G-edgesij=1; G-edgesji=1; /若为无向图,矩阵为对称矩阵;若建立有向图,去掉该条语句 /=定义标志向量,为全局变量=typedef enumFALSE,TRUE Boolean;Boolean visitedMaxVertexNum;/=DFS:深度优先遍历的递归算法=void DFSM(MGra
25、ph *G,int i) /以Vi为出发点对邻接矩阵表示的图G进行DFS搜索,邻接矩阵是0,1矩阵 int j; printf(%c,G-vexsi); /访问顶点Vi visitedi=TRUE; /置已访问标志 for(j=0;jn;j+) /依次搜索Vi的邻接点if(G-edgesij=1 & ! visitedj) DFSM(G,j); /(Vi,Vj)E,且Vj未访问过,故Vj为新出发点void DFS(MGraph *G) int i; for(i=0;in;i+)visitedi=FALSE; /标志向量初始化 for(i=0;in;i+)if(!visitedi) /Vi未访问
26、过 DFSM(G,i); /以Vi为源点开始DFS搜索/=BFS:广度优先遍历=void BFS(MGraph *G,int k) /以Vk为源点对用邻接矩阵表示的图G进行广度优先搜索 int i,j,f=0,r=0; int cqMaxVertexNum; /定义队列 for(i=0;in;i+)visitedi=FALSE; /标志向量初始化 for(i=0;in;i+)cqi=-1; /队列初始化 printf(%c,G-vexsk); /访问源点Vk visitedk=TRUE; cqr=k; /Vk已访问,将其入队。注意,实际上是将其序号入队 while(cqf!=-1) /队非空则
27、执行 i=cqf; f=f+1; /Vf出队 for(j=0;jn;j+) /依次Vi的邻接点Vj if(G-edgesij=1 & !visitedj) /Vj未访问 printf(%c,G-vexsj); /访问Vj visitedj=TRUE; r=r+1; cqr=j; /访问过Vj入队 /=main=void main() MGraph *G; G=(MGraph *)malloc(sizeof(MGraph); /为图G申请内存空间 CreatMGraph(G); /建立邻接矩阵 printf(Print Graph DFS: ); DFS(G); /深度优先遍历 printf(n
28、); printf(Print Graph BFS: ); BFS(G,3); /以序号为3的顶点开始广度优先遍历 printf(n);2邻接链表作为存储结构程序#includestdio.h#includestdlib.h#define MaxVertexNum 50 /定义最大顶点数typedef struct node /边表结点 int adjvex; /邻接点域 struct node *next; /链域EdgeNode;typedef struct vnode /顶点表结点 char vertex; /顶点域 EdgeNode *firstedge; /边表头指针VertexNo
29、de;typedef VertexNode AdjListMaxVertexNum; /AdjList是邻接表类型typedef struct AdjList adjlist; /邻接表 int n,e; /图中当前顶点数和边数 ALGraph; /图类型/=建立图的邻接表=void CreatALGraph(ALGraph *G) int i,j,k; char a; EdgeNode *s; /定义边表结点 printf(Input VertexNum(n) and EdgesNum(e): ); scanf(%d,%d,&G-n,&G-e); /读入顶点数和边数 scanf(%c,&a)
30、 printf(Input Vertex string:); for(i=0;in;i+) /建立边表 scanf(%c,&a);G-adjlisti.vertex=a; /读入顶点信息G-adjlisti.firstedge=NULL; /边表置为空表 printf(Input edges,Creat Adjacency Listn); for(k=0;ke;k+) /建立边表 scanf(%d%d,&i,&j); /读入边(Vi,Vj)的顶点对序号s=(EdgeNode *)malloc(sizeof(EdgeNode); /生成边表结点s-adjvex=j; /邻接点序号为js-nex
31、t=G-adjlisti.firstedge;G-adjlisti.firstedge=s; /将新结点*S插入顶点Vi的边表头部s=(EdgeNode *)malloc(sizeof(EdgeNode); s-adjvex=i; /邻接点序号为is-next=G-adjlistj.firstedge; G-adjlistj.firstedge=s; /将新结点*S插入顶点Vj的边表头部 /=定义标志向量,为全局变量=typedef enumFALSE,TRUE Boolean;Boolean visitedMaxVertexNum;/=DFS:深度优先遍历的递归算法=void DFSM(AL
32、Graph *G,int i) /以Vi为出发点对邻接链表表示的图G进行DFS搜索 EdgeNode *p; printf(%c,G-adjlisti.vertex); /访问顶点Vi visitedi=TRUE; /标记Vi已访问 p=G-adjlisti.firstedge; /取Vi边表的头指针 while(p) /依次搜索Vi的邻接点Vj,这里j=p-adjvexif(! visitedp-adjvex) /若Vj尚未被访问 DFSM(G,p-adjvex); /则以Vj为出发点向纵深搜索p=p-next; /找Vi的下一个邻接点 void DFS(ALGraph *G) int i;
33、 for(i=0;in;i+)visitedi=FALSE; /标志向量初始化 for(i=0;in;i+)if(!visitedi) /Vi未访问过 DFSM(G,i); /以Vi为源点开始DFS搜索DFSM(G,i);/=BFS:广度优先遍历=void BFS(ALGraph *G,int k) /以Vk为源点对用邻接链表表示的图G进行广度优先搜索 int i,f=0,r=0; EdgeNode *p; int cqMaxVertexNum; /定义FIFO队列 for(i=0;in;i+)visitedi=FALSE; /标志向量初始化 for(i=0;in;i+)cqi=-1; /初始
34、化标志向量 printf(%c,G-adjlistk.vertex); /访问源点Vk visitedk=TRUE; cqr=k; /Vk已访问,将其入队。注意,实际上是将其序号入队 while(cqf!=-1) /队列非空则执行i=cqf; f=f+1; /Vi出队p=G-adjlisti.firstedge; /取Vi的边表头指针while(p) /依次搜索Vi的邻接点Vj(令p-adjvex=j) if(!visitedp-adjvex) /若Vj未访问过printf(%c,G-adjlistp-adjvex.vertex); /访问Vjvisitedp-adjvex=TRUE;r=r+1; cqr=p-adjvex; /访问过的Vj入队 p=p-next; /找Vi的下一个邻接点