图的遍历及生成树
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
• 由广度优先搜索得到的生成树,称为广度优先搜索 生成树。
思考2:若对非连通图进行遍历,得到的是什么? 得到的将是各连通分量的生成树,即图的生成森林。
生成树
V1 V1
V2 V4 V8 V5 V6
V3
V7
V2
V3
V4 V8
V5 V6
V7
(a)深度优先生成树
(b) 广度优先生成树
例:求下图的深度优先生成树和广度优先生成树。 v1 v2 v5 v3
void DFS(ALGraph G, int v) { ArcNode *p; visited[v] = 1; /*置已访问标记*/ printf("%d ", v); /*输出被访问顶点的编号*/ p = G.vertices[v].firstarc; /*p指向顶点v的第一个邻接点*/ while (p!=NULL) { if (visited[p->adjvex]==0) DFS(G, p->adjvex); /*若p->adjvex顶点未访问,递归访问它*/ p = p->nextarc; /*p指向顶点v的下一个邻接点*/ } }
起点
—照样借用visited [n ]
1 2 3
辅助数组 visited [n]
DFS 结果
0 1 2 3
0 0 0 0
1 0 0 0
1
1 0 0
1 1 1 0
1 1 1 1
v0 → v1 → v2 →v3
注意:在邻接表中,并非每个 链表元素(表结点)都被扫描 到, 因此遍历速度很快。
邻接表的DFS算法
G
H
广度优先 生成森林
F
C
B
M J L
E
K
小结
1.理解并掌握图的深度优先搜索和广度优先搜索两种遍历 算法及其性能分析;以及两种遍历所使用的辅助数据结构
(栈或队列)在遍历过程中所起的作用,能够确定两种遍
历所得到的顶点访问序列以及利用图的两种遍历设计算法 解决简单的应用问题。
2.理解并掌握生成树的概念,能画出给定的图深度优先和
的顶点都被访问到;
(2)若此时图中尚有顶点未被访问,则另选图
中一个未曾被访问的顶点作起始点;
(3)重复上述两步,直至图中所有顶点都被访 问到为止。 与树的先序遍历过程类似
详细过程:
1) 1.1 在访问图中某一起始顶点 v 后,由 v 出发,访问它的 任一邻接顶点 w1; 1.2 再从 w1 出发,访问与 w1邻接但还未被访问过的顶点 w2; 1.3 然后再从 w2 出发,进行类似的访问…… 直至到达所有 的邻接顶点都被访问过的顶点 u 为止。 2) 退回一步,退到前一次刚访问过的顶点,看是否还有其 它未被访问的邻接顶点: 2.1 如果有,则访问此顶点,之后再从此顶点出发,返回 第1)步的操作; 2.2 如果没有,就再退回一步进行搜索。 2.3 重复上述过程,直到连通图中所有顶点都被访问过为 止。
有邻接点
未访问过
分析:
在遍历图时,对图中每个顶点至多调用一次DFS函数, 因为一旦某个顶点被标志成已被访问,就不再从它出发进 行搜索。 因此,遍历图的过程实质上是对每个顶点查找其邻接 点的过程。其耗费的时间则取决于所采用的存储结构。
如果用邻接矩阵来表示图,遍历图中每一个顶点都要从 头扫描该顶点所在行,因此遍历全部顶点所需的时间为 O(n2)。
visited[v] = TRUE; Visit(v);
EnQueue(Q, v); // v入队
while (!QueueEmpty(Q)) { DeQueue(Q, u); // 队头元素出队并置为u for (w=FirstAdjVex(G,u); w>=0; w=NextAdjVex(G,u,w)) if ( ! visited[w]){ //w为u的尚未访问的邻接顶点 visited[w] = TRUE; Visit(w); EnQueue(Q, w); } //if
如果用邻接表来表示图,虽然有 2e 个表结点,但只需扫 描 e 个结点即可完成遍历,加上访问 n个头结点的时间, 因此遍历图的时间复杂度为O(n+e)。
2.广度优先搜索(BFS, Breadth_First Search)
基本思想: 从图中某个顶点V0出发,并在访问此顶点后依次
访问V0的所有未被访问过的邻接点,之后按这些顶
连通图:仅需从图中任一顶点出发,进行深度优 先搜索(或广度优先搜索),便可访问到图中所 有顶点。 非连通图:需从多个顶点出发进行搜索,而每一 次从一个新的起始点出发进行搜索过程中得到的顶 点访问序列恰为其各个连通分量中的顶点集。
基本概念
生成树:某连通分量的极小连通子图,它含有图中
全部顶点,但只有n-1条边 ;
解决方案:附设访问标志数组visited[0..n-1],它的初 始状态为0,在图的遍历过程中,一旦某一个顶点i 被访问,就立即改 visited [i]为1,防止它被多次访问。
1.深度优先搜索(DFS, Depth_First Search ) 基本思想:(1)从图中某顶点V0出发,访问此顶 点,然后依次从V0的各个未被访问的邻接点出发深 度优先搜索遍历图,直至图中所有和V0有路径相通
v8
BFS非递归算法
void BFSTraverse(Graph G, Status (*Visit)(int v)){
//使用辅助队列Q和访问标志数组visited[v]
for (v=0; v<G.vexnum; ++v) visited[v] = FALSE; InitQueue(Q); // 置空的辅助队列Q for ( v=0; v<G.vexnum; ++v ) if ( !visited[v]) { // v尚未访问
} //while
}//if } // BFSTraverse
分析: 每个顶点至多进一次队列。遍历图的过程实质 上是通过边或弧找邻接点的过程,因此广度优先 搜索遍历图的时间复杂度和深度优先搜索遍历相 同,两者不同之处仅仅在于对顶点访问的顺序不 同。 邻接矩阵:O(n2) 邻接表:O(n+e)
第 7章 图
v4
v8
v6
v7
对非连通图,每个连通分量中的顶点集和遍历时走过的 边一起构成若干棵生成树,这些连通分量的生成树组成非 连通图的生成森林。
例:
一个连通图的生成树可能不唯一,由不同的遍历 次序、从不同顶点出发进行遍历都会得到不同的生 成树。
A
B C F D J E I
G
H
K
深度优先 生成森林
L
M
A D I
生成森林:非连通图的各个连通分量的极小连通子 图(即生成树)构成的集合,含全部顶点,但构成 这些树的边是最少的。
思考1:若对连通图进行遍历,得到的是什么?
遍历过程中历经的边的集合和图G中所有顶点一起 构成连通图G的极小连通子图,即图的生成树。 • 由深度优先搜索得到的生成树,称为深度优先搜索 生成树。
v2
v5 v4 v8 v6
v3
v7
v5, v6, v7, v8
用邻接表实现图的广度优先搜索 v1 v2 v5 v4 v8 v6 v3
0 1 2 3 4 5 6 7
v1 v2 v3 v4 v5 v6 v7 2 1 3^ 2 3 5 7^ 7^ 6^ 5^ 4^ 4^ 6^
v7
0 0 1 1 2 2
3
用邻接表实现图的深度优先搜索
v1 v2 v5 v3 0 1 2 3 4 5 6 7 8 9
1 2 3 2 1 0 2 3 ^ 3 5 7 ^ 7 ^ 6^ 5 ^ 4 ^ 4 ^
0
1 1 2
6 ^
4
5 6 7 8 9 10
v4
v8
v6
v9
v7 v10
2
3 9 /\ 8 /\
在图的邻接表中如何进行DFS? 例: 0
7.1 图的定义和术语
7.2 图的存储结构
7.3 图的遍历
7.4 图的连通性问题 7.5 有向无环图及其应用 7.6 最短路径
7.4 图的连通性问题
1)无向图的连通分量和生成树 2)最小生成树
普里姆算法
克鲁斯卡尔算法
1.无向图的连通分量和生成树
无向图的连通性 要想判定一个无向图是否为连通图,或有几个连通 分量,通过对无向图遍历即可得到结果。
}
void DFS (Graph G, int v) { //从第v个顶点出发递归地深度优先遍历图G visited[v]=TRUE ; Visit(v); //访问第v个顶点 //对v的尚未访问的邻接顶点w递归调用DFS for(w=FirstAdjVex(G,v); w>=0; w=NextAdjVex(G,v,w)) if (!visited[w]) DFS(G,w); }
期末考试
长春工业大学 >> 数据结构精品课程网站 >> 习题解析 http://jsj.ccut.edu.cn/sjjg/index.php?option=com_co ntent&task=category§ionid=&id=21&Itemid=266
7.3 图的遍历
从图中某一顶点出发访遍图中其余顶点,且使 每一个顶点仅被访问一次。这一过程就叫做图的 遍历。 抽象操作,可以是对结点进行的各种 处理,这里简化为输出结点的数据。
图的遍历操作要解决的关键问题 1、 在图中,如何选取遍历的起始顶点? 解决方案:从编号小的顶点开始 。 在图中,任何两个顶点之间都可能存在边,顶点是没 有确定的先后次序的,所以,顶点的编号不唯一。 这里指按顶点的存储顺序。
2、 因图中可能存在回路,在访问完某个顶点之后会沿 着某些边又回到了曾经访问过的顶点。那么如何避免顶 点的重复访问?
广度优先生成树或生成森林;
作业
基于邻接矩阵的DFS算法实现 基于邻接矩阵的BFS算法实现
点被访问的先后次序依次访问它们的邻接点,直至
图中所有和V0有路径相通的顶点都被访问到;
若此时图中尚有顶点未被访问,则另选图中一个 未曾被访问的顶点作起始点;
重复上述过程,直至图中所有顶点都被访问பைடு நூலகம்为
止。 与树的层次遍历过程类似
例:从顶点v1出发,BFS下图。 v1
访问序列:
v1, v2, v3, v4,
访问序列:
例:从顶点v1出发,DFS下图。
v1 v2 v5 v4 v8 v6 v7 v3
v1, v2, v4, v8, v5, v3, v6, v7
图的DFS算法一般描述
int visited[MAXVEX]; //访问标志数组
void DFSTraverse(Graph G) { //对图G作深度优先遍历 for( v=0; v<G.vexnum; ++v ) visited[v]=FALSE; //访问标志数组初始化0 for( v=0; v<G.vexnum; ++v ) if( !visited[v] ) DFS(G,v); //对尚未访问的顶点调用DFS
邻接矩阵的DFS算法
DFS1(MGraph G, int v) { //G.arcs[n][n]为邻接矩阵,v为起始顶点(编号) //访问(例如打印)顶点v visit(v); visited[v]=1;
//访问后立即修改辅助数组标志
for( j=0; j<G.vexnum; j++) //从v所在行从头搜索邻接点 if ( G.arcs[v][ j] && ! visited[j] ) DFS1(G, j); } // DFS1 G.arcs[v][j] =1 visited [n]=0