算法设计技巧与分析(六):图遍历(Graph Traversal)


图遍历(Graph Traversal)

一、深度优先搜索(Depth-First Search)

深度优先搜索如下图所示:

在这里插入图片描述
树边:深度优先搜索树的边
回边:所有其他边

算法伪代码如下:

Input: 无向图G=(V, E);
Output: 对应深度优先搜索树中顶点的预排序和后排序
predfn = 0
postfn = 0
for 每个点v属于V:
	标记v为unvisited
for 每个点v属于V://防止存在不连通图
	if v is unvisited:
		dfs(v)

def dfs(v):
	标记v为visited
	predfn = predfn + 1//节点搜索顺序
	for 每条边(v,w)属于E:
		if w is unvisited:
		dfs(w)
	postfn = postfn + 1//回溯顺序

搜索完成后,每个顶点都被predfn和postfn标记,它们给出了访问顶点的开始和结束的顺序。

假设图G的节点数为n,边数为m。
对于for 每个点v属于V中的if v is unvisited ,在循环内的时间复杂度为O(1),在算法执行结束后遍历每个节点,故为O(n)。
对于dfs(v)中的for 每条边(v,w)属于E ,算法执行结束后运行的次数为O(m)。对于有向图是m次,对于无向图是2m次。

综上,对于for 每个点v属于V://防止存在不连通图 ,算法执行结束后循环了O(m+n)次,故算法的时间复杂度为O(m+n)。

二、寻找关节点(Finding Articulation Points in a Graph)

寻找图中关节点是深度优先搜索的一个简单应用。

对于无向图G,存在一个顶点v,如果有不同于v的两个顶点u和w,在它们之间的任何路径都必须经过顶点v,则称v为关节点。即如果G是连通图,移去v和他相关的边,将会变得不连通。

算法思想:
首先对G进行一次深度搜索遍历,遍历过程中对每个顶点v都保持两个标号:A[v]、B[v],其中A[v]为predfn,B[v]为以下三个中的最小值:

  • A[v]
  • A[u],(v,u)为回边
  • B[w],在深度优先搜索树中的每条边(v,w)

关节点确定如下:

  • 根是关节点当且仅当在深度优先搜索他有两个或多个儿子(不算回边)
  • 除根以外的节点v是关节点当且仅当v有一个儿子使得B[w]>=A[v]

算法伪代码如下:

Input: 无向图G=(V, E);
Output: 包含G的所有可能关节点数组A[1....count]
predfn = 0
rootdegree = 0//根节点的度
count = 0//关节点数
for 每个点v属于V:
	标记v为unvisited
for 每个点v属于V://防止存在不连通图
	if v is unvisited:
		artpoint(v)

def artpoint(v):
	标记v为visited
	predfn = predfn + 1//节点搜索顺序
	A[v] = predfn
	B[v] = predfn
	isart = false
	for 每条边(v,w)属于E:
		if (v,w)是树边:
			if w is unvisited:
			artpoint(w)
			if v = s:
				rootdegree++
				if rootdegree == 2:
					isart = true
				else:
					B[v] = min{B[v],B[w]}
					if B[w] >= A[v]:
						isart = true
		else if (v,w)是回边:
			B[v] = min{B[v],A[w]}
	if isart:
		count++
		A[count] = v

在搜索从某个顶点w回退到v时,要做两条判断:

  • 如果发现B[w]比B[v]小,B[v]被设为B[w]
  • 如果发现B[w]比A[v]大或相等,那么此时v就是一个关节点,因为从w到v的祖先顶点必经过v。
    在这里插入图片描述
    从以w为根的子树到u的任何路径都需要经过v。在这个图中u是关节点,因为他的度大于1。

例子:
在这里插入图片描述
在这里插入图片描述

三、广度优先搜索(Depth-First Search)

广度优先搜索如下图所示:

在这里插入图片描述

这种遍历方法可以通过队列来实现,以存储未检查的顶点。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值