有向图、无向图是否有环的判断


今天在做数据库的调度冲突可串行性判别的程序,中间要用到有向图中环判定的问题,特摘录如下。这些算法和思想都是来自网上的,在此感谢原作者!

先介绍一下无向图的判断算法,这个比较简单:

判断无向图中是否存在回路(环)的算法描述

如果存在回路,则必存在一个子图,是一个环路。环路中所有顶点的度>=2

算法:

     第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度减一。

     第二步:将度数变为1的顶点排入队列,并从该队列中取出一个顶点重复步骤一。

     如果最后还有未删除顶点,则存在环,否则没有环。

算法分析:

            由于有m条边,n个顶点。如果m>=n,则根据图论知识可直接判断存在环路。

    (证明:如果没有环路,则该图必然是k棵树 k>=1。根据树的性质,边的数目m = n-k。k>=1,所以:m<n)

            如果m<n 则按照上面的算法每删除一个度为0的顶点操作一次(最多n次),或每删除一个度为1的顶点(同时删一条边)操作一次(最多m次)。这两种操作的总数不会超过m+n。由于m<n,所以算法复杂度为O(n)

 


接下来介绍有向图是否有环的判定算法,主要有深度优先和拓扑排序2中方法。

 

 1、拓扑排序,如果能够用拓扑排序完成对图中所有节点的排序的话,就说明这个图中没有环,而如果不能完成,则说明有环。

    2、可以用Strongly Connected Components来做,我们可以回忆一下强连通子图的概念,就是说对于一个图的某个子图,该子图中的任意u->v,必有v->u,则这是一个强连通子图。这个限定正好是环的概念。所以我想,通过寻找图的强连通子图的方法应该可以找出一个图中到底有没有环、有几个环。

    3、就是用一个改进的DFS

    刚看到这个问题的时候,我想单纯用DFS就可以解决问题了。但细想一下,是不能够的。如果题目给出的是一个无向图,那么OK,DFS是可以解决的。但无向图得不出正确结果的。比如:A->B,A->C->B,我们用DFS来处理这个图,我们会得出它有环,但其实没有。

    我们可以对DFS稍加变化,来解决这个问题。解决的方法如下:

    图中的一个节点,根据其C[N]的值,有三种状态:

    0,此节点没有被访问过

    -1,被访问过至少1次,其后代节点正在被访问中

    1,其后代节点都被访问过。

    按照这样的假设,当按照DFS进行搜索时,碰到一个节点时有三种可能:

    1、如果C[V]=0,这是一个新的节点,不做处理

    2、如果C[V]=-1,说明是在访问该节点的后代的过程中访问到该节点本身,则图中有环。

    3、如果C[V]=1,类似于2的推导,没有环。    在程序中加上一些特殊的处理,即可以找出图中有几个环,并记录每个环的路径


上面这个算法我没看懂。。所以没实现,但是自己用DFS实现了环检测。


		// DFS,发现回路(返回true)则不可序列化,返回false
		for (int i = 1; i <= n; i++) {
			if (dfsCheckCircuit(i))
				return false;
		}

	// 如果发现回路则返回true,否则遍历结束返回false
	private boolean dfsCheckCircuit(int current) {
		if (walked[current]) {
			return true;
		}
		walked[current] = true;
		for (int i = 1; i <= n; i++)
			if (digraph[current][i]) {
				if (dfsCheckCircuit(i)) {
					return true;
				}
			}
		walked[current] = false;
		return false;
	}
  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
判断无向图是否有环可以使用深度优先搜索(DFS)或广度优先搜索(BFS)算法来实现。这里给出一个使用DFS算法的伪代码来判断无向图是否有环: 1. 创建一个visited数组来记录每个顶点的访问状态,并初始化为未访问。 2. 对于图中的每个顶点v,如果v尚未被访问,则调用一个DFS函数来检测从v开始的路径是否存在环路。 3. 在DFS函数中,首先将当前顶点v标记为已访问。 4. 然后,对于v的每个邻接顶点u,如果u未被访问,则递归调用DFS函数来检测从u开始的路径是否存在环路。 5. 如果u已经被访问,并且u不是v的父节点(可以通过传递一个额外的参数来追踪父节点),则说明存在环路,返回true。 6. 如果对于v的所有邻接顶点都没有发现环路,则返回false。 以下是示例代码: ```python def has_cycle(graph, v, parent, visited): visited[v] = True for u in graph[v]: if not visited[u]: if has_cycle(graph, u, v, visited): return True elif parent != u: return True return False def is_cyclic(graph): num_vertices = len(graph) visited = [False] * num_vertices for v in range(num_vertices): if not visited[v]: if has_cycle(graph, v, -1, visited): return True return False ``` 其中,graph是一个邻接表表示的无向图,visited是一个记录顶点访问状态的数组,-1表示根节点没有父节点。 这样,调用is_cyclic函数即可判断无向图是否存在环路。如果返回True,则表示存在环路;如果返回False,则表示不存在环路。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值