1、 《数据结构》课程设计报告 设计题目 图的遍历演示 学生姓名 XXX 学生班级 XXXXX 学生学号 XXXXXX 指导教师 XXXXX 完成时间 2015 年 12 月26 日 1.1问题描述 从图中某个顶点出发访问图中所有顶点,且使得每一顶点仅被访问一次,这个过程称为图的遍历。图的遍历是从图中某个顶点出发,沿着某条搜索路径对图中其余每个顶点进行访问, 并且使图中的每个顶点仅被访问一次的过程。 图的遍历是图运算中最重要的运算,也是图的基本运算之一,图的许多运算都是以遍历为基础的。试编写一个程序,完成对
2、图的遍历。 1.2基本要求 1.以邻接矩阵为存储结构,实现无向图的深度优先遍历和广度优先遍历。 2.分别输出每种遍历下的结点访问序列.从图中某个顶点出发,沿着某条搜索路径对图中每个顶点各做一次且仅做一次访问。它是许多图的算法的基础。 图的遍历介绍 基本概念 图的遍历: 图中某个顶点出发访问图中所有顶点,且使得每一顶点仅被访问一次,这个过程称为图的遍历。图的遍历是从图中某个顶点出发,沿着某条搜索路径对图中其余每个顶点进行访问, 并且使图中的每个顶点仅被访问一次的过程。 图的遍历是图运算中最重要的运算,也是图的基本运算之一,图的许多运算都是以遍历为基础的。
3、 1.3.2、 分类 按照搜索途径的不同,图的遍历可分为:深度优先遍历(Depth-First Traverse)和广度优先遍历(Breadth-First Traverse)两大类。深度优先遍历和广度优先遍历是最为重要的两种遍历图的方法。 (1)深度优先遍历 (Depth-First Traverse) 特点:尽可能先对纵深方向的顶点进行访问 ① .深度优先遍历的递归定义 假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w
4、若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。 图的深度优先遍历类似于树的前序遍历。采用的搜索方法的特点是尽可能先对纵深方向进行搜索。这种搜索方法称为深度优先搜索(Depth-First Search)。相应地,用此方法遍历图就很自然地称之为图的深度优先遍历。 ② . 深度优先搜索的过程 a 基本思想: 首先访问图中某一个指定的出发点Vi; 然后任选一个与顶点Vi相邻的未被
5、访问过的顶点Vj; 以Vj为新的出发点继续进行深度优先搜索,直至图中所有顶点均被访问过。 b具体过程: 设x是当前被访问顶点,在对x做过访问标记后,选择一条从x出发的未检测过的边(x,y)。若发现顶点y已访问过,则重新选择另一条从x出发的未检测过的边,否则沿边(x,y)到达未曾访问过的y,对y访问并将其标记为已访问过;然后从y开始搜索,直到搜索完从y出发的所有路径,即访问完所有从y出发可达的顶点之后,才回溯到顶点x,并且再选择一条从x出发的未检测过的边。上述过程直至从x出发的所有边都已检测过为止。此时,若x不是源点,则回溯到在x之前被访问过的顶点;否则图中所有和源点有
6、路径相通的顶点(即从源点可达的所有顶点)都已被访问过,若图G是连通图,则遍历过程结束,否则继续选择一个尚未被访问的顶点作为新源点,进行新的搜索过程。 (2)广度优先遍历(Breadth-First Traverse): 特点:尽可能先从指定的出发点,横向地访问图中各个顶点。 ① .广度优先遍历的定义 在访问了起始点之后,首先依次访问起始点的各个邻接点,然后依次访问那些顶点中未被访问过的邻接点.依此类推,直到所有被访问到的顶点的邻接点都被访问过为止. ② .广度优先搜索的过程 a算法基本思想: 首先访问图中某一指定的出发点Vi; 然后依次访问Vi
7、的所有接点Vi1,Vi2…Vit; 再次访问Vi1,Vi2…,Vit的邻接点中未经访问过的顶点,依此类推,直到图中所有顶点均被访问为止。 b具体过程: 从广度优先搜索遍历方法可知,先被访问的顶点的邻接点也被访问,即假设顶点V在W之前被访问,那么顶点V的所有未经访问的邻接点也在顶点W的所有未经访问的邻接点之前被访问。这样可以在广度优先遍历的算法中设置一个队列结构,用以保存已访问过的顶点的序号,访问该顶点的所有未经访问的顶点。 广度优先搜索是一种分层的搜索过程,每向前走一步可能访问一批顶点,不像深度优先搜索那样会出现回退的现象。因此它不是个递归的过程。为了实现逐层访问
8、算法中使用了一个队列以记忆正在访问的这一层和上一层的顶点,以便于向下一层访问。为了避免重复访问,需要一个辅助函数visitvex[]给被访问过的顶点加标记。 2.概要设计 2.1算法说明 邻接矩阵作为存储结构的程序示例 #include"stdio.h" #include"stdlib.h" #define MaxVertexNum 100 //定义最大顶点数 typedef struct{ char vexs[MaxVertexNum]; //顶点表 int edges[MaxVertexNum][MaxVertexNum];
9、//邻接矩阵,可看作边表 int n,e; //图中的顶点数n和边数e }MGraph; //用邻接矩阵表示的图的类型 //=========建立邻接矩阵======= 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"
10、a);
printf("Input Vertex string:");
for(i=0;i
11、\n");
for(k=0;k
12、DFS:深度优先遍历的递归算法======
void DFSM(MGraph *G,int i)
{ //以Vi为出发点对邻接矩阵表示的图G进行DFS搜索,邻接矩阵是0,1矩阵
int j;
printf("%c",G->vexs[i]); //访问顶点Vi
visited[i]=TRUE; //置已访问标志
for(j=0;j
13、 //(Vi,Vj)∈E,且Vj未访问过,故Vj为新出发点
}
void DFS(MGraph *G)
{
int i;
for(i=0;i
14、FS(MGraph *G,int k)
{ //以Vk为源点对用邻接矩阵表示的图G进行广度优先搜索
int i,j,f=0,r=0;
int cq[MaxVertexNum]; //定义队列
for(i=0;i
15、Vk
visited[k]=TRUE;
cq[r]=k; //Vk已访问,将其入队。注意,实际上是将其序号入队
while(cq[f]!=-1) { //队非空则执行
i=cq[f]; f=f+1; //Vf出队
for(j=0;j
16、); //访问Vj visited[j]=TRUE; r=r+1; cq[r]=j; //访问过Vj入队 } } } //==========main===== void main() { int i; MGraph *G; G=(MGraph *)malloc(sizeof(MGraph)); //为图G申请内存空间 CreatMGraph(G); //建立邻接矩阵 printf("Print Grap
17、h DFS: "); DFS(G); //深度优先遍历 printf("\n"); printf("Print Graph BFS: "); BFS(G,3); //以序号为3的顶点开始广度优先遍历 printf("\n"); } 执行顺序: V6 V4 V5 V7 V2 V3 V1 V0 Vo 图G的示例 Input VertexNum(n) and EdgesNum(e): 8,9 Input Vertex string:
18、01234567 Input edges,Creat Adjacency Matrix 0 1 0 2 1 3 1 4 2 5 2 6 3 7 4 7 5 6 Print Graph DFS: 01374256 Print Graph BFS: 31704256 1. 邻接链表作为存储结构程序示例 #include"stdio.h" #include"stdlib.h" #define MaxVertexNum 50 //定义最大顶点数 typedef struct node{ //边表结点 int adjvex;
19、 //邻接点域 struct node *next; //链域 }EdgeNode; typedef struct vnode{ //顶点表结点 char vertex; //顶点域 EdgeNode *firstedge; //边表头指针 }VertexNode; typedef VertexNode AdjList[MaxVertexNum]; //AdjList是邻接表类型 typedef struct { AdjList adjlist; //邻接表
20、 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);
21、//读入顶点数和边数
scanf("%c",&a);
printf("Input Vertex string:");
for(i=0;i
22、e;k++) { //建立边表 scanf("%d%d",&i,&j); //读入边(Vi,Vj)的顶点对序号 s=(EdgeNode *)malloc(sizeof(EdgeNode)); //生成边表结点 s->adjvex=j; //邻接点序号为j s->next=G->adjlist[i].firstedge; G->adjlist[i].firstedge=s; //将新结点*S插入顶点Vi的边表头部 s=(EdgeNode *)malloc(sizeof(EdgeNod
23、e)); s->adjvex=i; //邻接点序号为i s->next=G->adjlist[j].firstedge; G->adjlist[j].firstedge=s; //将新结点*S插入顶点Vj的边表头部 } } //=========定义标志向量,为全局变量======= typedef enum{FALSE,TRUE} Boolean; Boolean visited[MaxVertexNum]; //========DFS:深度优先遍历的递归算法====== void DFSM(ALGra
24、ph *G,int i) { //以Vi为出发点对邻接链表表示的图G进行DFS搜索 EdgeNode *p; printf("%c",G->adjlist[i].vertex); //访问顶点Vi visited[i]=TRUE; //标记Vi已访问 p=G->adjlist[i].firstedge; //取Vi边表的头指针 while(p) { //依次搜索Vi的邻接点Vj,这里j=p->
25、adjvex
if(! visited[p->adjvex]) //若Vj尚未被访问
DFSM(G,p->adjvex); //则以Vj为出发点向纵深搜索
p=p->next; //找Vi的下一个邻接点
}
}
void DFS(ALGraph *G)
{
int i;
for(i=0;i
26、 //Vi未访问过
DFSM(G,i); //以Vi为源点开始DFS搜索
}
//==========BFS:广度优先遍历=========
void BFS(ALGraph *G,int k)
{ //以Vk为源点对用邻接链表表示的图G进行广度优先搜索
int i,f=0,r=0;
EdgeNode *p;
int cq[MaxVertexNum]; //定义FIFO队列
for(i=0;i
27、ted[i]=FALSE; //标志向量初始化 for(i=0;i<=G->n;i++) cq[i]=-1; //初始化标志向量 printf("%c",G->adjlist[k].vertex); //访问源点Vk visited[k]=TRUE; cq[r]=k; //Vk已访问,将其入队。注意,实际上是将其序号入队 while(cq[f]!=-1) { 队列非空则执行 i=cq[f]; f=f+1; //Vi
28、出队 p=G->adjlist[i].firstedge; //取Vi的边表头指针 while(p) { //依次搜索Vi的邻接点Vj(令p->adjvex=j) if(!visited[p->adjvex]) { //若Vj未访问过 printf("%c",G->adjlist[p->adjvex].vertex); //访问Vj visited[p->adjvex]=TRUE; r=r+1; cq[r]=p->adjvex; //访问过的Vj入队 }
29、 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
30、 "); BFS(G,3); printf("\n"); } 执行顺序: Input VertexNum(n) and EdgesNum(e): 8,9 Input Vertex string: 01234567 V6 V4 V5 V7 V2 V3 V1 V0 Vo 图G的示例 Input edges,Creat Adjacency List 0 1 0 2 1 3 1 4 2 5 2 6 3 7 4 7 5 6 Print Graph DFS: 02651473 Print Graph
31、BFS: 37140265 一、 修改后的代码 1. 邻接矩阵作为存储结构的程序 #include"stdio.h" #include"stdlib.h" #define MaxVertexNum 100 //定义最大顶点数 typedef struct{ char vexs[MaxVertexNum]; //顶点表 int edges[MaxVertexNum][MaxVertexNum]; //邻接矩阵,可看作边表 int n,e; //图中的顶点数n和边数e }MGraph;
32、 //用邻接矩阵表示的图的类型 //=========建立邻接矩阵======= 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;
33、i
34、d",&i,&j); //输入边(Vi,Vj)的顶点序号 G->edges[i][j]=1; G->edges[j][i]=1; //若为无向图,矩阵为对称矩阵;若建立有向图,去掉该条语句 } } //=========定义标志向量,为全局变量======= typedef enum{FALSE,TRUE} Boolean; Boolean visited[MaxVertexNum]; //========DFS:深度优先遍历的递归算法====== void DFSM(MGraph *G,int i) { //以Vi为出发点对邻接矩
35、阵表示的图G进行DFS搜索,邻接矩阵是0,1矩阵
int j;
printf("%c",G->vexs[i]); //访问顶点Vi
visited[i]=TRUE; //置已访问标志
for(j=0;j
36、 int i;
for(i=0;i
37、 int i,j,f=0,r=0;
int cq[MaxVertexNum]; //定义队列
for(i=0;i
38、序号入队
while(cq[f]!=-1) { //队非空则执行
i=cq[f]; f=f+1; //Vf出队
for(j=0;j
39、j; //访问过Vj入队 } } } //==========main===== void main() { MGraph *G; G=(MGraph *)malloc(sizeof(MGraph)); //为图G申请内存空间 CreatMGraph(G); //建立邻接矩阵 printf("Print Graph DFS: "); DFS(G); //深度优先遍历 printf("\n"); pr
40、intf("Print Graph BFS: "); BFS(G,3); //以序号为3的顶点开始广度优先遍历 printf("\n"); } 2. 邻接链表作为存储结构程序 #include"stdio.h" #include"stdlib.h" #define MaxVertexNum 50 //定义最大顶点数 typedef struct node{ //边表结点 int adjvex; //邻接点域 struct node *next; //链域 }
41、EdgeNode; typedef struct vnode{ //顶点表结点 char vertex; //顶点域 EdgeNode *firstedge; //边表头指针 }VertexNode; typedef VertexNode AdjList[MaxVertexNum]; //AdjList是邻接表类型 typedef struct { AdjList adjlist; //邻接表 int n,e; //图中当前顶点数和边数 } ALGrap
42、h; //图类型 //=========建立图的邻接表======= 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("Inpu
43、t Vertex string:");
for(i=0;i
44、 //读入边(Vi,Vj)的顶点对序号 s=(EdgeNode *)malloc(sizeof(EdgeNode)); //生成边表结点 s->adjvex=j; //邻接点序号为j s->next=G->adjlist[i].firstedge; G->adjlist[i].firstedge=s; //将新结点*S插入顶点Vi的边表头部 s=(EdgeNode *)malloc(sizeof(EdgeNode)); s->adjvex=i; //邻接点序号为i
45、s->next=G->adjlist[j].firstedge; G->adjlist[j].firstedge=s; //将新结点*S插入顶点Vj的边表头部 } } //=========定义标志向量,为全局变量======= typedef enum{FALSE,TRUE} Boolean; Boolean visited[MaxVertexNum]; //========DFS:深度优先遍历的递归算法====== void DFSM(ALGraph *G,int i) { //以Vi为出发点对邻
46、接链表表示的图G进行DFS搜索 EdgeNode *p; printf("%c",G->adjlist[i].vertex); //访问顶点Vi visited[i]=TRUE; //标记Vi已访问 p=G->adjlist[i].firstedge; //取Vi边表的头指针 while(p) { //依次搜索Vi的邻接点Vj,这里j=p->adjvex if(! visited[p->adjvex]) //若Vj尚未被访问
47、 DFSM(G,p->adjvex); //则以Vj为出发点向纵深搜索
p=p->next; //找Vi的下一个邻接点
}
}
void DFS(ALGraph *G)
{
int i;
for(i=0;i
48、S搜索
DFSM(G,i);
}
//==========BFS:广度优先遍历=========
void BFS(ALGraph *G,int k) { //以Vk为源点对用邻接链表表示的图G进行广度优先搜索
int i,f=0,r=0; EdgeNode *p; int cq[MaxVertexNum]; //定义FIFO队列 for(i=0;i
49、>n;i++) cq[i]=-1; //初始化标志向量 printf("%c",G->adjlist[k].vertex); //访问源点Vk visited[k]=TRUE; cq[r]=k; //Vk已访问,将其入队。注意,实际上是将其序号入队 while(cq[f]!=-1) { //队列非空则执行 i=cq[f]; f=f+1; //Vi出队 p=G->adjlist[i].firstedge; //取Vi的边表头指针
50、 while(p) { //依次搜索Vi的邻接点Vj(令p->adjvex=j) if(!visited[p->adjvex]) { //若Vj未访问过 printf("%c",G->adjlist[p->adjvex].vertex); //访问Vj visited[p->adjvex]=TRUE; r=r+1; cq[r]=p->adjvex; //访问过的Vj入队 } p=p->next; //找Vi的下一个邻接点 }
©2010-2025 宁波自信网络信息技术有限公司 版权所有
客服电话:4009-655-100 投诉/维权电话:18658249818