有没有一种有效的算法来检测有向图中的循环?
我有一个有向图,表示需要执行的作业计划,作业是一个节点,依赖项是一个边。我需要检测这个图中导致循环依赖关系的循环的错误情况。
有没有一种有效的算法来检测有向图中的循环?
我有一个有向图,表示需要执行的作业计划,作业是一个节点,依赖项是一个边。我需要检测这个图中导致循环依赖关系的循环的错误情况。
当前回答
如果一个图满足这个性质
|e| > |v| - 1
那么图至少包含一个周期。
其他回答
Tarjan的强连通分量算法的时间复杂度为O(|E| + |V|)。
有关其他算法,请参见维基百科上的强连接组件。
从DFS开始:当且仅当DFS期间发现后边缘时,循环存在。这是白径定理的结果。
如果DFS发现一条边指向一个已经访问过的顶点,那么这里就有一个循环。
https://mathoverflow.net/questions/16393/finding-a-cycle-of-fixed-length我最喜欢这个解决方案,特别是4个长度:)
物理向导还说你必须做O(V^2)。我相信我们只需要O(V)/O(V+E)。 如果图是连通的,那么DFS将访问所有节点。如果图有连通的子图,那么每次我们在这个子图的顶点上运行DFS时,我们都会找到连通的顶点,并且不必为下一次运行DFS考虑这些。因此,对每个顶点运行的可能性是不正确的。
如果你不能给节点添加一个“被访问过”的属性,使用一个集合(或者映射),把所有被访问过的节点添加到集合中,除非它们已经在集合中。使用唯一的键或对象的地址作为“键”。
这还为您提供了关于循环依赖项的“根”节点的信息,当用户必须修复问题时,这些信息将派上用场。
另一个解决方案是尝试找到下一个要执行的依赖项。为此,您必须有一个可以记住您现在在哪里以及接下来需要做什么的堆栈。在执行依赖项之前,检查它是否已经在此堆栈上。如果是,你就找到了一个循环。
虽然这看起来可能有O(N*M)的复杂度,但你必须记住,堆栈的深度非常有限(所以N很小),而且随着你可以检查为“已执行”的每个依赖项,M会变得越来越小,加上你可以在找到叶子时停止搜索(所以你永远不必检查每个节点-> M也会很小)。
在MetaMake中,我将图表创建为列表列表,然后在执行它们时删除每个节点,这自然地减少了搜索量。实际上,我从来不需要运行一个独立的检查,这一切都是在正常执行过程中自动发生的。
如果你需要一个“仅测试”模式,只需添加一个“干运行”标志,它禁止实际作业的执行。