查找有向图中所有圈的算法加速策略

简介

有向图G(V,E),圈是一个起始节点与终止节点相同的路径,即 a->….->a。找到所有的圈可能要遍历所有的路径,这就涉及到算法性能的考虑。本文基于深度优先搜索,讨论查找所有圈的算法加速策略。

无向图的查圈算法

深度优先搜索算法是从已知节点出发,图的一种遍历算法。只要一个节点被同源两个路径访问,这两个路径则形成一个圈。因为每个节点只处理一次,所以时间与空间复杂度都是O(N)。其算法如下:

DFS(a) for undirected graph

stack.push(a)

while not stack.empty

i = stack.pop

mark i as accessed

{j} = adjacent(i)

stack.push({j where j is not accessed })

对于无向图来说,每个 i的邻节点 j ,如果已经 accessed,那么形成一个圈。注意此时并不知道圈中的每个节点是什么。因此算法要针对有向图改造,而且要记录圈中的每个节点,每个圈都不能遗漏,还要保持高性能。

有向图的查圈算法

对于有向图来说,要记录从 a 到 i 的路径,才能判断 i的邻接点j 是否形成一个圈。算法如下:

DFS(a) for directed graph

stack.push(<{a}, 0>) //采用 stack 记录路径

while not stack.empty

<set, k> = stack.top

mark set[k++] not in stack // in-stack为路径标记

if set[k] in stack

record(set[k], stack) //在stack中找到圈上所有节点

continue

mark set[k] in stack // set[k]为当前路径上的节点

if k>|set|

stack.pop

else

stack.push(<adjacent(set[k]), 0>)

这个算法遍历了所有从 a 出发的路径,满足了查找圈的功能,不会遗漏任何一个圈。然而要穷举所有路径,这个算法通常会很慢,需要采用一些加速策略。

查圈算法的加速策略

通常的策略是对图的简化,各种情况如下:

  • 0入度、0出度的节点:直接消除。因为所有在圈上的节点的入度和出度数都大于1。这是一个迭代的过程,因为消除一个可能产生另外一个。如果与邻接点形成一个圈,记录下来,直接消除。
  • 相邻的1入度节点和1出度节点:合并。因为通过其中一个节点必通过另外一个节点。
    •   特殊情况,2度节点,即1入1出的节点。可以形成一个长链,合并成一个节点;也可能与另外节点形成一个圈,直接记录下来。

另一个策略是一边查找,一边合并在一个圈上的节点。节点在一个圈上,这是一个等价关系。合并节点可以提高圈套圈情况下的查找性能;还可以混合使用各种查圈算法。例如,无向图的查圈算法速度不错,但是会遗漏一些圈,因此可以放在有向图的查圈算法之前执行。

还有一种策略是对图建立一系列简化图,即建立简化映射,然后对简化图进行查圈操作。当查圈操作和其它应用操作需要混合处理时,这种策略的算法更清晰。

开发加速策略,需要注意两点:

  1. 关注有向图的统计信息,采取有针对性地加速策略。
  2. 对于大型图,很难单步调试。需要自动检测一些约束条件来保证操作的正确性,这方面可参照“最弱前置条件”。

结语

这个问题没有查到更好的解决方案,主要采用图简化策略来加速算法,结果还不错。

时间: 2024-10-13 23:29:16

查找有向图中所有圈的算法加速策略的相关文章

查找有向图中所有的环

在对每个结点进行DFS的基础上进行了一些优化. 优化原理:若findCycle(0,e), 找到一个0-2-3的环,那么不再对2.3进行findCycle()函数.因为2或3若是构成有其它的环,findCycle(0)回溯到2或3时,会找出这些环. 1 import java.util.*; 2 3 public class GetAllCyclesForDirectedGraph{ 4 static List<Integer> trace; 5 static Set<Integer&g

判断有向图是否有圈

1. 拓扑排序 拓扑排序是对有向无圈图的顶点的一种排序:如果存在一条vi到vj的路径,则vj排在vi后面(因为只要满足这个特性就是拓扑序列,所以它不一定是唯一的).比如在众多的大学课程中,有些课有先修课,我们可以将其抽象为拓扑排序,有向边(v, w)表明课程v必须安排在w之前,否则课程w就无法进行.我们可以想象所有的课程以及课与课之间的关系可以用一个图来表示,而拓扑排序就可以知道课程安排的顺序.然而,如果图存在圈,就没有拓扑序列.比如如果要上课程A必须上课程B,要上课程B必须上课程C,而要上课程

有向图中单个源点到终点的最短路径--Dijkstra算法与实现

1.Dijkstra算法能够解决有向图中单个源点到另一终点的最短路径问题,它的算法过程如下: 1)用矩阵graph[]N[N](N为图中节点个数)表示带权的有向图G.若图中两个节点vi和vj是连通的,则graph[i][j]表示这两个节点之间边的权值:若两节点vi和vj不是连通的,则graph[i][j] = -1. 2)设S为从某点start_vec开始的最短路径path的终点集合,初始状态时,集合S中只有起始节点start_vec.设从起始节点start_vec到其余节点vi的最短路径长度为

《数据结构、算法与应用》8.(顺序查找数组中第一个出现指定元素的位置)

最近在读<数据结构.算法与应用>这本书,把书上的习题总结一下,用自己的方法来实现了这些题,可能在效率,编码等方面存在着很多的问题,也可能是错误的实现,如果大家在看这本书的时候有更优更好的方法来实现,还请大家多多留言交流多多指正,谢谢 8. 从左至右检查数组a[0:n-1]中的元素,以查找雨x相等的那些元素.如果找到一个元素与x相等,则函数返回x第一次出现所在的位置.如果在数组中没有找到这样的元素,函数则返回-1. // // main.cpp // Test_08 // // Created

算法系列15天速成——第五天 五大经典查找【中】

原文:算法系列15天速成--第五天 五大经典查找[中] 大家可否知道,其实查找中有一种O(1)的查找,即所谓的秒杀. 哈希查找: 对的,他就是哈希查找,说到哈希,大家肯定要提到哈希函数,呵呵,这东西已经在我们脑子里面形成 固有思维了.大家一定要知道“哈希“中的对应关系. 比如说: ”5“是一个要保存的数,然后我丢给哈希函数,哈希函数给我返回一个”2",那么此时的”5“ 和“2”就建立一种对应关系,这种关系就是所谓的“哈希关系”,在实际应用中也就形成了”2“是key,”5“是value. 那么有的

经典算法详解(11)递归查找数组中的最大值

题目:编写一个程序,用递归的方法实现查找数组中的最大值. C++实现 1 #include<iostream> 2 3 using namespace std; 4 //第一种方法是常规方法,不是使用递归,首先将第一个元素的值赋值给max,然后遍历数组, 5 //当遇到超高max的值时将其赋值给max,最后就将得到最大值 6 int getMax_fir(int *arr,int n) { 7 int max = arr[0]; 8 for (int i = 1; i < n; i++)

求有向图的强连通分量的算法

下面是求有向图的强连通分量的算法的代码: import java.util.Scanner; class Qiufenliang//定义求强连通分量的类 { String lu="";//定义的一个字符型变量,记录强连通分量的路径 public static int s=0; public void qiu(int a[][],int l)//定义函数,参数a为二维数组,参数l为数组的维数 { int t=0;//定义int型变量,进行数量的统计 for(int i=1;i<l;

【转载】有向图强连通分量的Tarjan算法

from byvoid [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达.{5},{6}也分别是两个强连通分量. 直接根据定义,用双向遍历取交集的方法求强连通分量,时间复杂度为

算法笔记_144:有向图强连通分量的Tarjan算法(Java)

目录 1 问题描述 2 解决方案 1 问题描述 引用自百度百科: 如果两个顶点可以相互通达,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树.搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量. 定义D