还有一个常见的问题就是检测图中是否存在环?这也是一个很有意思的问题,因为在大多数图的结构中确实是存在环的。对于一个连通的图来说,如果它不存在环,则可以称其为树了(如下文),因此环检测的问题在判断一个图是否为树的问题上有很重要的应用。从图中构成环的任意一个节点开始,如果按照某个方向遍历,最终它某个可以访问的点是它前面已经遍历过的。对于一些特殊的情况,比如两个相邻的节点之间的连接,它们不能定义为环,需要被排除:可以增加一个参数,表示访问的当前节点的前一个节点,如果从当前节点所能连接到的节点去遍历的时候,碰到的节点是已经访问过的节点,但是这个节点是它的前一个节点的话,这种情况不能定义为环,我们应该忽略。如果对于图并不是完全连通的情况呢?为了避免遗漏,肯定要尝试去遍历所有的节点,和前面检测图连通性类似。
1
2
3
4
5
① 遍历所有连通块,记录 prev 节点,同时进行访问标记
② 如果从当前节点所能连接的节点去遍历时,碰到的节点是已经访问过的
(1) 这个节点是当前节点的 prev 节点,不是环
(2) 不是 prev 节点,是环
当环存在时,可以通过 prevs[] 数组返回这个环
上述方法仅使用于无向图,对于如下的有向图并不适用:利用上述算法会在节点⑥时检测到环,实际上并不存在环。
因此对于有向图,需要对上述算法做以下的补充。
1
2
3
4
5
6
③ 找到一个还在遍历中的节点,同时在遍历的时候它如果再次被访问到了,则表示找到了环;如果它被访问完了之后返回,则再次碰到它的时候就不是环了
(1)bool onStack[]:
1.1 对这个节点访问前设置,表示在一个递归顺序
1.2 访问退出这个递归后,设置回来
(2)bool visited[]:记录访问过的节点
(3)int prevs[]:记录环的结果,通过记录前后访问的节点来回溯得到环
能够用拓扑排序(下一节)完成对图中所有节点的排序的话,就说明这个图中没有环;如果不能完成,则说明有环。
DAG: 拓扑排序