码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2016-12-01 13:49:20      阅读:384      评论:0      收藏:0      [点我收藏+]

标签:复杂   产生   深度优先   top   统计   过程   sed   信息   统计信息   

简介

有向图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. 对于大型图,很难单步调试。需要自动检测一些约束条件来保证操作的正确性,这方面可参照“最弱前置条件”。

结语

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

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

标签:复杂   产生   深度优先   top   统计   过程   sed   信息   统计信息   

原文地址:http://www.cnblogs.com/liuyunfeng/p/6121465.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!