第九章 图的遍历算法
第三部分 最先割技术
第九章 图的遍历
第九章 图的遍历
9.1 引言 9.2 深度优先搜索 9.3 深度优先搜索的应用 9.4 广度优先搜索 9.5 广度优先搜索的应用
9.1 引 言
在一些诸如找出最短路径和最小生成树的图 的算法中,用由它们相应的算法顺序访问顶点 和边。然而,在一些其他算法中,访问顶点的 顺序是不重要的,重要的是,不管输入的图如 何,用一种系统的顺序来访问顶点。在本章中, 我们讨论图遍历的两种方法:深度优先搜索和 广度优先搜索。
1、 根是一个关节点当且仅当在深度优先搜索树中, 它有两个或更多的儿子;
原因:图中不存在连接不同子树顶点的边,删掉根 结点后,生成树就变成了森林。
2、 根以外的其他结点V,如果其某棵子树的根和 子树中的其他结点均没有指向该结点v的祖先的回 边。 或者:根以外的顶点v是一个关节点当且仅当v有 一个儿子w,使得β(w)≥α(v)。
见例9.3。
a
i
d
c
b
g
h
e
f
j
1,1 a
2,1 b
3,3 c
f
6,1
g
7,1
d 4,3
8,8 h
e 5,3
i 9,8
j 10,8
(1)初始化各个顶点;
(2)从a-e开始搜索,一直到e均是正常搜索, 各个数值依次递增增长;
(3)搜索到e时,找到一个回边(e,c),则e 的β(e)=min{a[c]=3;a[e]=5,β[c]=3}=3;
过程 dfs(v) 1. 标记v已访问;artpoint false; //关节点标记 predfn predfn+1//标记序号
2. α(v) predfn; β(v) predfn //初始化访问序号
3. For 每条边(v,w)∈E 4. If (v,w)为树边 then 5. dfs(w) //深入开始访问后续结点 6. If v=s then //树根结点
我们将假设在这种有向无回路图中有一个入度 是0的唯一的顶点s,如果不是的话,我们可以简 单地添一个新的顶点s,然后让s到所有入度为0的 点加上边。
a
c
e
s
b
d
g f
接下来,我们从顶点s起,简单地对图G执行 深度优先搜索。
当遍历完成时,计数器postdfn定义了一个在 有向无回路图中顶点的反扑排序,于是,为了得 到这个拓扑序,可以在算法DFS中在计数器 postdfn刚好被增加后,加上一个输出步,把输出 结果翻转过来就是我们需要的拓扑序。
3,3 c
f
6,8
g
7,7
d 4,2
8,6 h
e 5,1
i 9,5
j 10,4
2、有向图的情况
有向图中的深度优先搜索导致结果:
一个或多个(有向)生成树,树的多少取决于 初始点。
(1)选择某起始点v,深度优先搜索一棵树, 它由从v出发所有可到达的顶点组成。
(2)没有遍历完所有的顶点,选择另一个顶 点w继续(未访问过顶点),构建一颗从w可到达 的所有未访问顶点组成的树,这个过程继续下去 直到所有的顶点都被访问过。
19. A[count] v
20. End if
(1)首先,算法执行必要的初始化,特别 地,count是关节点的个数,rootdegree是深度优 先搜索树根的度,这在后来决定根是否是关节点 时是需要的。
(2)接着深度优先搜索从根开始着手,对于 每一个访问的顶点v, α(v)和 β(v)用predfn来初始 化。
(4)回退至d点时,该点的β[d]=3;(原来是4);
(5)回退到c点,β[c]=3,由于β[d]>=a[c],所以 该结点是关节点。
(6)回退到b结点,β[c]>=a[b],所以b也是一个 关节点。
此(j,h)是一个回边,所以将
β[j]=a[h]=8;
(2)回到i点,该点的β[i]也被改为8; (3)同理,对于h点来讲,其β[h]也被置为8;
此时,由于β[i]>a[h],所以h是关节点; (4)回退到g点,同样存在β[h]>a[g],所以该点 也是关节点;检测到该点存在回路,所以将其 β[g]值置为其祖先结点的值=1; (5)β[f] β[b]也被置为1,搜索回到a结点,因为 a结点只有一个分支孩子,所以a不是关节点
(注意:测试方法是要依次搜索该点的邻接 点,看是否从某个点访问过它,所以是(n))
(4)测试顶点w是否标记为未访问,这一步 的执行次数等于顶点v的邻接点数。
这一步执行的总次数,在有向图的情况下等 于它的边数,在无向图的情况下是边数的两倍。
于是,不论是有向图还是无向图,这一步的 耗费是(m),
(5)算法的总运行时间是:(m+n)。如果图 是连通的或有m≥n,则运行时间简单地为(m)。但 是必须强调的是,图假设是用邻接表表示的。
为关节结点
12.
Endif
13. Else if (v,w)是回边 then //v!=s
β(v) min{β(v), α(w)}
14.
Else do nothing { w是v的父亲}
15. End if
16. End for
17. If artpoint then
18. count count+1
4、在访问过程中,按照上述的深度优先的方 式向前推进,一旦发现某一个顶点X的所有邻 接点都被标志为已访问,访问指针回退至上一 层,继续访问该层没有被访问的其他的子节点。
5、如此往复,直至回退到根节点为止。
算法9.1 DFS
Input: 有向或无向图G=(V,E)。 Output: 在相应的深度优先搜索树中对顶点的前序
算法9.3 STRONGCONNECTCOMP
INPUT:有向图G=(V,E)
OUTPUT:G中的强连通分支
1. 在图G上执行深度优先搜索,对每一个顶点赋
算法9.2 ARTICPOINTS
INPUT:连通无向图G=(V,E)。 OUTPUT:包含G的所有可能关节点的数组 A[1…n]。
1.设s为起始顶点 2.for 每个顶点v∈V 3. 标记v未访问 4.end for //初始化全部结点为没有访问
5.predfn 0;count 0;rootdegree 0 6.dfs(s) //从初始结点开始访问
(3)在搜索从某顶点w退回到v时,要做两件 事,首先,如果发现β(w)比β(v)小,β(v)被设置为 β(w),其次,如果β(w)≥α(v),那么这就指出v是 一个关节点,因为从w到v的祖先顶点必须经过v。
这说明在图9.4种,可以看到,从以w为根的子 树到u的任何路径必定包括v,因此v是一个关节点。 以w为根的子树包含一个或多个连通分支。在这 个图中,根u是关节点,因为它的度大于1。
9.3.3 寻找图的关节点
关节点:
在多于两个顶点的无向图G中,存在一个顶点 v,如果有不同于v的两个顶点u和w,在u和w间的 任何路径都必定经过顶点v。
这样,如果G是连通的,移去v和与它关联的边, 将产生G的非连通子图(森林)。一个图如果是 连通的并且没有关节点则称为是双连通的。
由深度优先生成树的特性可以得到如下结论:
(3)重复上述过程,直至所有顶点被访问完 毕。
G的边分成4种类型:
1、树边:深度优先搜索树中的边。如果在搜索边 (v,w)时,w是第一次被访问,则(v,w)是树边。
2、回边:在迄今为止构建的深度优先搜索树中, w是v的祖先,并且当搜索(v,w)时顶点w已被标上 已访问,这样形成的边(v,w)是回边。
9.2.1 深度优先搜索的时间复杂性
(1)顶点v被访问标记为访问的过程,每一个顶 点的调用耗费是(1)。一共需要n个顶点,所以该 过程的总耗费是(n)。 (2)算法的步骤1和步骤3分别耗费(1) 和(n) 时间。//初始化序列号、访问标志 (3)步骤6测试一个顶点是否已标记要耗费(n)。
和后序。
1. predfn 0;postdfn 0 2. For 每个顶点v∈V 3. 标记v未访问 //初始化访问标志
4. End for 5. For 每个顶点v∈V 6. If v未访问 then dfs(v) //调用访问
7. End for
过程 dfs(v) //递归访问
1. 标记v已访问
3、前向边:在迄今为止构建的深度优先搜索树中, w是v的后裔,并且当搜索(v,w)时顶点w被标上已 访问,这种形式的边(v,w)是前向边。
3、横跨边:所有其它的边。
见例9.2。
c
b
a
d
e
f
1,4 a
2,3 b e 3,1
5,6 c
2,2 f
f
d
e
4,2
6,5
3,1
1,4 a
5,6 c
b 4,3
d 6,5
9.3 深度优先搜索的应用
深度优先搜索在图和几何算法中用得很普遍。 在本节中,我们列举它的一些重要应用。
9.3.1 图的无回路性 设G=(V,E)是一个有n个顶点和m条边的有向或
无向图。为了测试G是否至少有一个回路,我们 对G用深度优先搜索,如果在搜索过程中探测到 一条回边,那么G是有回路的,否则G是无回路的。
2、森林(顶点不相连,不能够一次都到达)。
1、无向图的情况分析
设G=(V,E)是无向图,作为遍历的结果,G的边 分成一下两种类型。
树边:深度优先搜索树中的边,如果在搜索边 (v,w)时,w是首次被访问,则边(v,w)是树边。 回边:所有其它的边。
例9.1。
a
i
d
c
b
g
h
e
f
j
1,10 a
2,9 b
a
i
d
c
b