5.3 图的遍历演示
【图论课件】第二课时·图的遍历
大意:在一个神奇的图中,对于每个点所在 路径求最小环
Luogu P2921
在之前的基础上分析:首先不能按照联通 块求了,而要每个点分别求出最小环。 但是直接搜索显然太睿智,所以需要利用 算过的结果来优化。先画一张适用于大部分 情况的路径图。
Luogu P2921
出度为1,考虑利用路径的唯一性。除了 染色和时间戳,还可以将环外与环分类讨论。
Luogu P2661
图的遍历是O(n)的。用时间戳记录第一 次到达的时间(形象理解)。当遇到之前到 达过的点时,用当前时间-时间戳就得到了这 个环的大小。 遍历时染色以避免多次搜索。如果遇到之 前染过色的点(时间戳不为0的点),跳出。 (据说用并查集很简单)
Luogu P2921 [USACO08DEC]在农 场万圣节Trick or Treat on the Farm
大意:在一个神奇的图中找最小环大小。
Luogu P2661
这好像是个很弱的图——每个点出度皆为 1!正因为如此,每当选定一个起始点,就已 经确定了之后的所有路径。 这也导致了一个特点:从任意一个点出发, 总能够遍历这个点所属联通块(形象理解) 的最小环。该命题易证(滑稽)。 于是,现在问题就简化为分别在每个联通 块中求最小环。
课程小结
图的遍历一般使用DFS,少用BFS。 不重不漏地经过所有边是欧拉路,如果又 回到起点是欧拉回路。求解要注意细节。 时间戳可以在遍历时帮助计算大小。
环外优化:记录之后入环时间,记为ic。 环优化:记录最小环大小,记为mc。
Luogu P2921
这部分的代码基本相同,只是在找到环时 更新起点的ic与mc数组。 优化的部分是之前遍历过时,利用唯一性 优化。同样分两类:在环中、不在环中。
图的遍历
第3讲图的遍历——教学讲义图的遍历就是从图中的某个顶点出发,按某种方法对图中的所有顶点访问且仅访问一次。
图的遍历比起树的遍历要复杂得多。
由于图中顶点关系是任意的,即图中顶点之间是多对多的关系,图可能是非连通图,图中还可能有回路存在,因此在访问了某个顶点后,可能沿着某条路径搜索后又回到该顶点上。
为了保证图中的各顶点在遍历过程中访问且仅访问一次,需要为每个顶点设一个访问标志,因此要为图设置一个访问标志数组visited[n],用于标示图中每个顶点是否被访问过,它的初始值为0(假),一旦顶点v i访问过,则置visited[i]为1(真),以表示该顶点已访问。
对于图的遍历,通常有两种方法,即深度优先搜索和广度优先搜索。
1 深度优先搜索深度优先搜索(Depth_First Search,DFS)是指按照深度方向搜索,它类似于树的先根遍历,是树的先根遍历的推广。
深度优先搜索的基本思想是:(1)从图中某个顶点v0出发,首先访问v0。
(2)找出刚访问过的顶点的第一个未被访问的邻接点,然后访问该顶点。
以该定点为新顶点,重复此步骤,直到刚访问过的顶点没有未被访问的邻接点为止。
(3)返回前一个访问过的且仍有未被访问的邻接点的顶点,找出该顶点的下一个未被访问的邻接点,访问该顶点。
然后执行步骤(2)。
下图给出了一个深度优先搜索的过程图示,其中实箭头代表访问方向,虚箭头代表回溯方向,箭头旁边的数字代表搜索顺序,A为起始顶点。
首先访问A,然后按图中序号对应的顺序进行深度优先搜索。
图中序号对应步骤的解释如下:(1)顶点A的未访邻接点有B、E、D,首先访问A的第一个未访邻接点B;(2)顶点B的未访邻接点有C、E,首先访问B的第一个未访邻接点C;(3)顶点C的未访邻接点只有F,访问F;(4)顶点F没有未访邻接点,回溯到C;(5)顶点C已没有未访邻接点,回溯到B;(6)顶点B的未访邻接点只剩下E,访问E;(7)顶点E的未访邻接点只剩下G,访问G;(8)顶点G的未访邻接点有D、H,首先访问G的第一个未访邻接点D;(9)顶点D没有未访邻接点,回溯到G;(10)顶点G的未访邻接点只剩下H,访问H;(11)顶点H的未访邻接点只有I,访问I;(12)顶点I没有未访邻接点,回溯到H;(13)顶点H已没有未访邻接点,回溯到G;(14)顶点G已没有未访邻接点,回溯到E;(15)顶点E已没有未访邻接点,回溯到B;(16)顶点B已没有未访邻接点,回溯到A。
图遍历的演示(DOC)
约瑟夫环实验报告一.需求分析1、以邻接多重表为存储结构;2、实现连通和非连通的无向图的深度优先和广度优先遍历;3、要求利用栈实现无向图的深度优先遍历;4、以用户指定的结点为起点,分别输出每种遍历下的结点访问序列和生成树的边集;5、用凹入表打印生成树;6、求出从一个结点到另外一个结点,但不经过另外一个指定结点的所有简单路径;二.概要设计1.设定图的抽象数据类型2. 栈的抽象数据类型定义3.队列的抽象数据类型定义三.详细设计程序设计如下:#include<stdio.h>#include <stdlib.h>#include<conio.h>#define MAXQUEUE 70 /* 伫列的最大容量*/struct node /* 图形顶点结构宣告*/{int vertex; /* 顶点资料*/struct node *nextnode; /* 指下一顶点的指标*/};typedef struct node *graph; /* 图形的结构新型态*/struct node head[61]; /* 图形顶点结构数组*/int visited[61]; /* 遍历记录数组*/int queue[MAXQUEUE]; /* 伫列的数组宣告*/int front = -1; /* 伫列的前端*/int rear = -1; /* 伫列的后端/* ---------------------------------------- *//* 建立图形*/ /* ---------------------------------------- */void creategraph(int *node,int num){graph newnode; /* 新顶点指标*/graph ptr;int from; /* 边线的起点*/int to; /* 边线的终点*/int i;for ( i = 0; i < num; i++ ) /* 读取边线的回路*/{from = node[i*2]; /* 边线的起点*/to = node[i*2+1]; /* 边线的终点/* 建立新顶点记忆体*/newnode = ( graph ) malloc(sizeof(struct node));newnode->vertex = to; /* 建立顶点内容*/newnode->nextnode = NULL; /* 设定指标初值*/ptr = &(head[from]); /* 顶点位置*/while ( ptr->nextnode != NULL ) /* 遍历至链表尾*/ptr = ptr->nextnode; /* 下一个顶点*/ptr->nextnode = newnode; /* 插入结尾*/}}/* ---------------------------------------- *//* 伫列资料的存入*/ /* ---------------------------------------- */int enqueue(int value)if ( rear >= MAXQUEUE ) /* 检查伫列是否全满*/return -1; /* 无法存入*/rear++; /* 后端指标往前移*/queue[rear] = value; /* 存入伫列*/}/* ---------------------------------------- *//* 伫列资料的取出*/ /* ---------------------------------------- */int dequeue(){if ( front == rear ) /* 检查伫列是否是空*/return -1; /* 无法取出*/front++; /* 前端指标往前移*/return queue[front]; /* 伫列取出*/}/* ---------------------------------------- *//* 图形的广度优先搜寻法*/ /* ---------------------------------------- */void bfs(int current){graph ptr;/* 处理第一个顶点*/enqueue(current); /* 将顶点存入伫列*/visited[current] = 1; /* 记录已遍历过*/printf("[%d] ",current); /* 印出遍历顶点值*/while ( front != rear ) /* 伫列是否是空的*/{current = dequeue(); /* 将顶点从伫列取出*/ptr = head[current].nextnode; /* 顶点位置*/while ( ptr != NULL ) /* 遍历至链表尾*/{if ( visited[ptr->vertex] == 0 ) /* 如过没遍历过*/{enqueue(ptr->vertex); /* 递回遍历呼叫*/visited[ptr->vertex] = 1; /* 记录已遍历过*//* 印出遍历顶点值*/printf("[%d] ",ptr->vertex);}ptr = ptr->nextnode; /* 下一个顶点*/}}}/* ---------------------------------------- *//* 图形的深度优先搜寻法*/ /* ---------------------------------------- */void dfs(int current){graph ptr;visited[current] = 1; /* 记录已遍历过*/printf("[%d] ",current); /* 印出遍历顶点值*/ptr = head[current].nextnode; /* 顶点位置*/while ( ptr != NULL ) /* 遍历至链表尾*/{if ( visited[ptr->vertex] == 0 ) /* 如过没遍历过*/dfs(ptr->vertex); /* 递回遍历呼叫*/ptr = ptr->nextnode; /* 下一个顶点*/}}/* ---------------------------------------- *//* 主程式: 建立图形后,将遍历内容印出. */ /* ---------------------------------------- */int main(){//clrscr();while(1){char c,a;graph ptr;int i;int node [60] [2] = { {1, 10}, {10, 1}, /* 边线数组*/{2, 10}, {10, 2},{2, 3}, {3, 2},{3, 4}, {4, 3},{3, 12}, {12, 3},{4, 13}, {13, 4}, {4, 5}, {5, 4}, {5, 6}, {6, 5}, {5, 7}, {7, 5}, {7, 8}, {8, 7}, {9, 10}, {10, 9}, {10, 11}, {11, 10}, {11, 14}, {14, 11}, {11, 12}, {12, 11}, {12, 15}, {15, 12}, {12, 13}, {13, 12}, {13, 16}, {16, 13}, {14, 17}, {17, 14}, {14, 18}, {18, 14}, {15, 19}, {19, 15}, {16, 20}, {20, 16}, {17, 18}, {18, 17}, {18, 23}, {23, 18}, {18, 19}, {19, 18}, {19, 23}, {23, 19}, {19, 24}, {24, 19}, {19, 20}, {20, 19},{20, 21}, {21, 20},{22, 23}, {23, 22},{24, 25}, {25,24}};//clrscr();printf("\n\n\n");printf(" 图的深度遍历和广度遍历? Y/N?\n");c=getch();if(c!='y'&&'Y')exit(0);//clrscr();printf("\n\n");printf("以下为各城市的代码:\n\n");printf("1:乌鲁木齐; 2:呼和浩特; 3:北京; 4:天津; 5:沈阳; \n");printf("6:大连; 7:长春; 8:哈尔滨; 9:西宁; 10:兰州;\n");printf("11:西安; 12:郑州; 13:徐州; 14:成都; 15:武汉; \n");printf("16:上海; 17:昆明; 18:贵阳; 19:株州; 20:南昌;\n");printf("21:福州; 22:南宁; 23:柳州; 24:广州; 25:深圳.\n");for (i=1;i<=25;i++ ){head[i].vertex=i; /* 设定顶点值*/head[i].nextnode=NULL; /* 清除图形指标*/visited[i]=0; /* 设定遍历初值*/}creategraph(node,60); /* 建立图形*/printf("图形的邻接链表内容:\n");for (i=1;i<=25;i++){ if(i%3==0)printf("\n");printf("顶点%d=>",head[i].vertex); /* 顶点值*/ptr=head[i].nextnode; /* 顶点位置*/while(ptr!=NULL) /* 遍历至链表尾*/{printf("%d ",ptr->vertex); /* 印出顶点内容*/ptr=ptr->nextnode; /* 下一个顶点*/}}printf("\n\n");printf("请选择你需要的操作\n");printf("1、图形的广度优先遍历请输入:'g'或'G'\n"); printf("2、图形的深度优先遍历请输入:'s'或'S'\n");c=getch();switch(c){case'g':case'G':printf("\n请你输入你需要的起始顶点:\n");scanf("%d",&i);///clrscr();printf("\n\n");printf("以下为各城市的代码:\n\n");printf("1:乌鲁木齐; 2:呼和浩特; 3:北京; 4:天津; 5:沈阳; \n");printf("6:大连; 7:长春; 8:哈尔滨; 9:西宁; 10:兰州;\n");printf("11:西安; 12:郑州; 13:徐州; 14:成都; 15:武汉; \n");printf("16:上海; 17:昆明; 18:贵阳; 19:株州; 20:南昌;\n");printf("21:福州; 22:南宁; 23:柳州; 24:广州; 25:深圳.\n");printf("图形的广度优先遍历的顶点内容:\n");bfs(i); /* 印出遍历过程*/printf("\n"); /* 换行*/break;case's':case'S':printf("\n请输入你需要的起始顶点:\n");scanf("%d",&i);//clrscr();printf("\n\n");printf("以下为各城市的代码:\n\n");printf("1:乌鲁木齐; 2:呼和浩特; 3:北京; 4:天津; 5:沈阳; \n");printf("6:大连; 7:长春; 8:哈尔滨; 9:西宁; 10:兰州;\n");printf("11:西安; 12:郑州; 13:徐州; 14:成都; 15:武汉; \n");printf("16:上海; 17:昆明; 18:贵阳; 19:株州; 20:南昌;\n");printf("21:福州; 22:南宁; 23:柳州; 24:广州; 25:深圳.\n");printf("图形的深度优先遍历的顶点内容:\n");dfs(i); /* 印出遍历过程*/printf("\n"); /* 换行*/break;}printf("\n请问你是否要继续:y/n");a=getch();if(a!='y'&&'Y')exit(0);}}四.调试分析1、本程序以邻接多重表为存储结构。
图遍历的演示 文档
图的遍历演示一、需求分析1. 以邻接多重表为存储结构;2. 实现连通和非连通的无向图的深度优先和广度优先遍历;3. 要求利用栈实现无向图的广度和深度优先遍历;4. 以用户指定的节点为起点,分别输出每种遍历下的节点访问序列和生成树的边表;5. 用凹入表打印生成树;6. 求出从一个节点到另一个节点,但不经过另外一个指定节点的所有简单路径。
二、概要设计ADT Queue {数据对象:D={ai|ai属于Elemset,i=1,2,……,n,n>=0}数据关系:R1={<ai-a,ai>ai-1属于D,i=1,2,…,n}约定ai为端为队列头,an为队列尾基本操作:InitQueue(&Q)操作结果:构造一个空队列QDestroyQueue(&Q)初始条件:队列Q已存在操作结果:队列Q被销毁,不再存在ClearQueue(&Q)初始条件:队列Q已存在操作结果:将Q清为空队列QueueEmpty(Q)初始条件:队列Q已存在操作结果:若Q为空队列,则返回TRUE,否则FALSEQueueLength(Q)初始条件:队列Q已存在操作结果:返回Q的元素个数,即队列的长度GetHead(Q,&e)初始条件:Q为非空队列操作结果:用e返回Q的队头元素EnQueue(&Q,e)初始条件:队列Q已存在操作结果:插入元素e为Q的新的队尾元素DeQueue(&Q,&e)初始条件:Q为非空队列操作结果:删除Q的队头元素,并用e返回其值三、详细设计1、顶点,边和图类型#define MAX_INFO 10 /* 相关信息字符串的最大长度+1 */#define MAX_VERTEX_NUM 20 /* 图中顶点数的最大值*/typedef char InfoType; /*相关信息类型*/typedef char VertexType; /* 字符类型 */typedef enum{unvisited,visited}VisitIf;typedef struct EBox{VisitIf mark; /* 访问标记 */int ivex,jvex; /* 该边依附的两个顶点的位置 */struct EBox *ilink,*jlink; /* 分别指向依附这两个顶点的下一条边 */ InfoType *info; /* 该边信息指针 */}EBox;typedef struct{VertexType data;EBox *firstedge; /* 指向第一条依附该顶点的边 */}VexBox;typedef struct{VexBox adjmulist[MAX_VERTEX_NUM];int vexnum,edgenum; /* 无向图的当前顶点数和边数 */}AMLGraph;2. 其它部分代码void BFSTraverse(AMLGraph G,VertexType start,int(*Visit)(VertexType)) { /*从start顶点起,广度优先遍历图G*/for(v=0;v<G.vexnum;v++)Visited[v]=0; /* 置初值 */InitQueue(Q);z=LocateVex(G,start); /*先确定起点start在无向图中的位置*/for(v=0;v<G.vexnum;v++)if(!Visited[(v+z)%G.vexnum]) /* v尚未访问 */{Visited[(v+z)%G.vexnum]=1; /* 设置访问标志为TRUE(已访问) */ Visit(G.adjmulist[(v+z)%G.vexnum].data);EnQueue(Q,(v+z)%G.vexnum);while(!QueueEmpty(Q)) /* 队列不空 */{DeQueue(Q,u);for(w=FirstAdjVex(G,G.adjmulist[u].data);w>=0;w=NextAdjVex(G,G.adjmulist[u].data,G.adjmulist[w].data)) if(!Visited[w]){Visited[w]=1;Visit(G.adjmulist[w].data);EnQueue(Q,w);}}}DestroyQueue(Q); /*销毁队列,释放其占用空间*/}3. 队列的基本操作:Status InitQueue(LinkQueue &Q);//构造一个空队列Q。
图的两种遍历
输入:
9 10 12 13 17 28 27 34 45 47 56 ram xy; var map:array[1..20,1..20] of integer; visited,q:array[1..100] of integer; //使用辅助队列Q和访问标志数组visited。 n,m,a,b,h,r,i,j:integer; procedure bfs(); //按广度优先非递归遍历图,n个顶点,编号为1..n。 var tmp:integer; begin while h<=r do begin tmp:=q[h]; //队头元素出队并置为tmp h:=h+1; write(tmp,' '); for j:=1 to n do if (map[tmp][j]=1) and (visited[j]=0) then //j为tmp的尚未访问的邻接顶点 begin visited[j]:=1;r:=r+1;q[r]:=j; end;//j入队列 end; end;
保证图中所有 顶点被访问
三、广(宽)度优先遍历
宽度优先遍历的基本思想为:
从图中某个顶点v0出发,访问此顶点。然后依次访问v0的 各个未被访问过的邻接结点,然后分别从这些邻接结点出发 宽度优先遍历图,直到图中所有和顶点v0连通的顶点都被访 问到。 若此时图中尚有顶点未被访问,则另选图中一个未曾被访 问的顶点作起始点,重复上述过程,直到图中所有顶点都被 访问到为止。
begin readln(n,m); for i:=1 to m do begin readln(a,b); map[a][b]:=1; map[b][a]:=1; end; for i:=1 to n do if visited[i]=0 then begin visited[i]:=1;work(i);end; end.
图的深度优先遍历(课堂PPT)
v1 v4
v5
3 V3
v1 v6
v7
4 V4 v2 v8
5 v5 6 v6 7 v7 8 v8
v2 v8 v3 v7 v3 v6 v4 v5
v,1
v,2
v1 v,4
v5
v2
v,8
v4
v,5
v2
v8
v3
23
0
1 v1
v2 v3
2 v2
v1 v4
v5
3 V3
v1 v6
v7
4 V4 v2 v8
5 v5 6 v6 7 v7 8 v8
5 v5 6 v6 7 v7 8 v8
v2 v8 v3 v7 v3 v6 v4 v5
v,1
v,2
v1 v,4
v5
v1
v2
v,8
v4
v,5
v2
v8
v,3 v6 v7
32
0
1 v1
v2 v3
2 v2
v1 v4
v5
3 V3
v1 v6
v7
4 V4 v2 v8
5 v5 6 v6 7 v7 8 v8
v2 v8 v3 v7 v3 v6 v4 v5
7.3图的遍历
回顾其他数据结构的遍历: • 顺序表的遍历 • 单链表的遍历 • 二叉树的遍历 展望: 那么对于图,我们怎样进行遍历呢? • 图的深度优先遍历 • 图的广度优先遍历
这两个算法是后面拓扑排序、求关键路径算法的基础
1
7.3.1.连通图的深度优先遍历
2
算法描述:
1.深度优先遍历以v开始的连通图
v7
4 V4 v2 v8
5 v5 6 v6 7 v7 8 v8
图的遍历
6
8 4 2 1
3.1 深度优先搜索遍历
1 2 4 5 8
1
栈
3 6 7
非递归
2
4
3
5
8
6
6 8 4 2 1
3.1 深度优先搜索遍历
1 2 4 5 8
1
栈
3 6 7
非递归
2
4
3
5
8
6
7
3 6 8 4 2 1
3.1 深度优先搜索遍历
1 2 4 5 8
1
栈
3 6 7
非递归
2
4
3
5
8
6
7
7的邻接 表空, 逐一退 栈
问过为止。
1 2 4 5 8 3 6 7
深度优先
1
2
4
3
所有都访 问完毕了
5
8
6
7
2已经访问返 回8
3.1 深度优先搜索遍历
下面以下图为例来讨论dfs算法的执行过程:调用dfs(1)
此箭头表示是从遍历运 算 dfs(1) 中调用 dfs(2) , 即从顶点1直接转到2
此虚箭头表示是在 dfs(3) 执行完毕后返回到遍历 运算 dfs(2) 中,即从顶点 3返回到2
1
2 3
以3为起点根本 不能遍历整个图
1
2
4
2
1 3
4 7 9 8
24
10
3
5
6
5
6
3.1 深度优先搜索遍历
3. 深度遍历算法的应用
问题: (1)如何设计算法以判断给定的无向图是否是连通的? (2)如何设计算法以求解给定的无向图中的边数? (3)设计算法以判断给定的无向图是树。 (4)设计算法以判断给定的有向图是以v0为根的有向树。 (5)设计算法以判断图中的一个节点是否为关节点。
图的遍历(深度优先遍历和广度优先遍历)
遍历规则 从图中某结点v0出发,深度优先遍历(DFS: Depth First Search)图的规则为: 访问v0; 对v0的各个出点v01,v02,…,v0m,每次从它们中按一定方式(也可任选)选取一个未被访问过的结点,从该结点出发按深度优先遍历方式遍历。 然,因为我们没有规定对出点的遍历次序,所以,图的深度优先遍历结果一般不唯一。
20.2 深度优先遍历
例如,对图 20‑1给出的有向图与无向图,一些遍历结果(结点访问次序)为: 左图:从1出发:1,2,4,5;或1,5,2,4 从2出发:2,1,5,4;或2,4,1,5 右图:从a出发:a,b,c,d;或a,b,d,c; … …
A 如果不想让visited或top做为函数参数,也可以在函数中将其定义为static型量。但是,这样的程序是不可再入的,即函数再次被调用时,static型的量也不重新初始化,造成错误!
上面函数中的参数visited和top实质上是中间变量,只是为了避免在递归调用时重新初始化而放在参数表中,造成使用的不方便,为此,做个包装程序: long DFS1(int g[][CNST_NumNodes], long n, long v0, long *resu ) { char *visited; long top=0; visited = new char[n]; for (long i=0; i<n; i++) visited[i]=0; long num=DFS1( g, n, v0, visited, resu, top ); delete visited; return num; }
深度优先遍历非递归算法的一般性描述。
long DFS_NR(图g,结点v0)
单击此处可添加副标题
数据结构课程设计--图的遍历
数据结构课程设计--图的遍历内蒙古科技大学本科生课程设计论文题目:图的遍历2013年07月05日内蒙古科技大学课程设计任务书目录第一章图的遍历原理51.1总述61.2深度优先遍历61.3广度优先遍历6第二章需求分析7第三章总体设计 (7)3.1程序设计思路 (7)3.2 功能视图 (8)第四章类的设计 (8)4.1 GraphUDN类的设计 (9)4.2 Queue类的设计 (10)第五章详细设计 (10)5.1 工程视图和类视图 (10)5.2 主要算法的流程图 (11)5.2.1 主函数的流程图 (11)5.2.2 深搜流程图 (12)5.2.3 广搜流程图 (13)第六章测试 (14)6.1 菜单界面 (15)6.2 创建无向网 (15)6.3 输出图 (16)6.4 输出顶点V的第一个邻接点 (16)6.5 输出顶点V的下一个邻接点 (17)6.6 深搜 (17)6.7 广搜 (18)第七章总结 (18)附录:程序代码 (20)参考文献 (29)第一章图的遍历原理1.1总述图的遍历:从图中某一顶点出发访遍图中其余顶点,且使得每一个顶点仅被访问一次。
这一过程就叫做图的遍历。
1.2深度优先遍历深度优先遍历类似于树的先根遍历,是树的先根遍历的推广。
假如初始状态是图中所有顶点未曾被访问,则深度优先遍历可从图中某个顶点V出发,访问此顶点,然后依次从V的未被访问的邻接点出发深度优先遍历图,直到图中所有和V有路径相通的顶点都被访问到;若图中此时尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直到图中所有顶点都被访问到为止。
以图1.1为例,假如从顶点V1出发进行搜索,在访问了顶点V1之后,选择邻接点V2。
因为V2未曾访问,则从V2出发进行搜索。
以此类推,接着从V4,V8,V5出发进行搜索。
在访问了V5之后,由于V5的邻接点都已被访问,则搜索回到V8。
由于同样的理由,搜索回到V4,V2直到V1,此时由于V1的另一个邻接点未被访问,则搜索又从V1到V3,再继续进行下去。
图的遍历演示
inputt.close();
}
}
三、实验结果:
1.输入图
2. 遍历图:(先深度,后广度)
四、结果分析:
数据结构顾名思义讲求的是一种存储结构,一路走来先后学习了表、树,最后学习的是图,对于每种存储结构学习之初都会学习一些基本操作,而操作之中又以创建和遍历为最基本的操作,只有熟练掌握了以后才能对其他操作进行研究和学习。
在这次实验中,我也得到了很多收获,比如链表的应用,以前弄不太明白,通过这次实验,在链表这一方面我懂了很多,虽然还不能运用自如,但在这次实验中,对本学期所学习的内容也是一次巩固,让我加深了对学过知识的记忆。
总之,这次实验让我既发现了自身的很多不足,又增长了很多知识。
图的遍历演示
2.广度优先搜索(遍历)步骤: 广度优先搜索(遍历)步骤: 广度优先搜索
简单归纳: 简单归纳:
• • • 在访问了起始点v之后, 的邻接点; 在访问了起始点 之后,依次访问 v的邻接点; 之后 的邻接点 然后再依次访问这些顶点中未被访问过的邻接点; 然后再依次访问这些顶点中未被访问过的邻接点; 直到所有顶点都被访问过为止。 直到所有顶点都被访问过为止。 广度优先搜索是一种分层的搜索过程, 广度优先搜索是一种分层的搜索过程,每向前走一 步可能访问一批顶点, 步可能访问一批顶点,不像深度优先搜索那样有回 退的情况。因此, 退的情况。因此,广度优先搜索不是一个递归的过 其算法也不是递归的。 程,其算法也不是递归的。
可以用递归算法! 可以用递归算法 讨论2 讨论2: DFS算法如何编程? ——可以用递归算法! DFS算法如何编程? 算法如何编程
void ExtMGraph <T>::DFS (int v, void *visit()) , //设A[n][n]为邻接矩阵,v为起始顶点(编号) //设A[n][n]为邻接矩阵, 为起始顶点(编号) 为邻接矩阵 { visit(v); ( ) //访问 例如打印)顶点v 访问( //访问(例如打印)顶点v visited[v]=1; //访问后立即修改辅助数组标志 //访问后立即修改辅助数组标志 //从v所在行从头搜索邻接点 //从 所在行从头搜索邻接点 从头 for( j=0; j<n; j++) if ( A[v, j] && ! visited[j] ) DFS (j, visit); , return; 深度优先 visited [j ]=0 A[v,j] =1 } // DFS
借助于队列实现
图的两种图的遍历方法
5.3 图的遍历和树的遍历类似,在此,我们希望从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次。
这一过程就叫做图的遍历(TraversingGraph)。
图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础。
然而,图的遍历要比树的遍历复杂得多。
因为图的任一顶点都可能和其余的顶点相邻接。
所以在访问了某个顶点之后,可能沿着某条路径搜索之后,又回到该顶点上。
[例如]图7.1(b)中的G2,由于图中存在回路,因此在访问了v1,v2,v3,v4之后,沿着边(v4 , v1)又可访问到v1。
为了避免同一顶点被访问多次,在遍历图的过程中,必须记下每个已访问过的顶点。
为此,我们可以设一个辅助数组visited[0..n-1],它的初始值置为“假”或者零,一旦访问了顶点vi,便置visited[i]为“真”或者为被访问时的次序号。
通常有两条遍历图的路径:深度优先搜索和广度优先搜索。
它们对无向图和有向图都适用。
5.3.1 深度优先搜索深度优先搜索(Depth-First Search)遍历类似于树的先根遍历,是树的先根遍历的推广。
其基本思想如下:假定以图中某个顶点vi为出发点,首先访问出发点,然后选择一个vi的未访问过的邻接点vj,以vj为新的出发点继续进行深度优先搜索,直至图中所有顶点都被访问过。
显然,这是一个递归的搜索过程。
现以图5-3-1中G为例说明深度优先搜索过程。
假定v0是出发点,首先访问v0。
因v0有两个邻接点v1、v2均末被访问过,可以选择v1作为新的出发点,访问v1之后,再找v1的末访问过的邻接点。
同v1邻接的有v0、v3和v4,其中v0已被访问过,而v3、v4尚未被访问过,可以选择v3作为新的出发点。
重复上述搜索过程,继续依次访问v7、v4 。
访问v4之后,由于与v4相邻的顶点均已被访问过,搜索退回到v7。
由于v7、v3和v1都是没有末被访问的邻接点,所以搜索过程连续地从v7退回到v3,再退回v1,最后退回到v0。
数据结构-图的遍历ppt
-
深度优先搜索-连通图
void DFS(Graph G, int v) {
// 从顶点v出发,深度优先搜索遍历连通图 G
visited[v] = TRUE; for(w=FirstAdjVex(G, v);
w>=0; w=NextAdjVex(G,v,w)) if (!visited[w]) DFS(G, w);
图的遍历
复习 图的遍历 深度优先搜索 广度优先搜索 课堂练习 小结和作业
-
复习-图的存储结构
B A
F
C D
E
010010 100011 000101 001001 110000 011100
-
复习-图的存储结构
B A
F
C D
E
0A
1B 2C 3D 4E 5F
1
4
0
4
5
3
5
2
5
0
1
1
2
3
-
复习-图的存储结构
}
-
邻接点函数的实现
int nextAdjVex(ALGragh G, int v, int w){ p=G.vertices[v].firstarc;//v的第1个邻接点 while(p && p->adjvex != w) p=p->nextarc; if(p) p = p->nextarc;//w之后的下一个邻接点 if(p) return p->adjvex; else return -1;}
// 对v的尚未访问的邻接顶点w递归调用DFS
} // DFS
余顶点,并且使图中的每个顶点仅被访问一次的过 程。
5-3图的遍历
N
Y
w已 被 访 问 过
N
dfs(W)
算法4.1 从顶点v0出发深度优先遍历g中能访问的各个顶点
w=nextadj(g,v0,w)
void dfs(int v0)
图 4.16 深 度 遍 历 算 法 流 程 图
{ visited[v0]=1; /*访问标志置为 1,表示已被访问*/
w=firstadj(g,v0); /* w是vo的第一个邻接点 */
点,将该结点作为当前结点,重复2,直到所有顶点被 访问过的为止
如图G4:
V1
深到底 访问 回退
V2
V3
深到底 (V2V8均已访问)深到底
V1V2V4V8V5
V3V6V7
回退
V4
V5 V6
V7
V8
深度优先遍历的递归算法:
访 问 v0 置 v0访 问 标 志 为 1
w=firstadj(g,v0)
w=0 Y
while (w!=0)
{ if(visited[w]==0) dfs(w); /*顶点未被访问,则递归的进行深度遍历 */
w=nextadj(g,v0,w) /*顶点已访问,则取顶点v0在w后面的下一个邻接点 */
}
}
几点说明:
1.visited[1..n]是一个辅助数组,记载顶点是否被访问过
visited[Vi]=
}
/* 从v0出发广度优先遍历图g */ /* 取队头元素v */ /* 求v的第一个邻接点 */
/* 求下一个邻接点 */
深度优先遍历结果/广度优先遍历结果与存 储方式的关系是什么?
深度优先遍历/广度优先遍历与生成树有关 系连通子图数量?
一、深度优先搜索DFS(depth-first-search)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
图的遍历演示 一.实验目的
[
问题描述]
很多涉及图上操作的算法都是以图的遍历为基础的。
试写一个程序,演示在连通的无向图上访问全部节点的操作。
[基本要求]
以邻接多重链表为存储结构。
实现连通无向图的深度和广度优先遍历。
以用户指定的节点为起点,分别输出每种遍历下的节点访问序列和相应生成树的边集。
二.实验内容 1、自定义数据类型
2、基本操作函数
3、主函数
三.实验思路
①首先访问起始顶点v,再访问图中与v相邻接的且未被访问过的任一顶点w1;
②再从w1出发,访问与w1相邻接的且未被访问过的任一顶点w2;
③从w2出发,重复与步骤②类似的访问,直至遇到一个所有邻接点均被访问过的顶点为止;
④沿刚才访问的次序,反向回到一个尚有邻接点未被访问过的顶点,再从该顶点出发,重复与步骤
③相类似的访问,直到所有的被访问过的顶点的邻接顶点均被访问过为止。
四.实验的结果及分析。
五.实验中出现的问题、解决方法和心得体会
本实验主要运用栈和图的知识,由于图掌握的不是很熟练,导致实验过程遇到困难很多,所以现在完成的这个实验还不是很完善,只能够实现深度优先搜索,我还将继续花多点时间研究一下广度优先搜索。
不过虽然还没完善,但基本功能已经实现且符合要求了。