如何检查有向图是否是非循环的?
如何检查有向图是否是非循环的? 以及该算法是如何调用的? 我希望能提供参考。
How do I check if a directed graph is acyclic? And how is the algorithm called? I would appreciate a reference.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
我会尝试对图进行拓扑排序,如果不能,那么它就有循环。
I would try to sort the graph topologically, and if you can't, then it has cycles.
进行简单的深度优先搜索不足以不足以找到循环。 在 DFS 中可以多次访问一个节点而不存在循环。 根据您开始的位置,您也可能不会访问整个图表。
您可以按如下方式检查图形的连接组件中的循环。 找到一个只有出边的节点。 如果不存在这样的节点,则存在环路。 在该节点上启动 DFS。 遍历每条边时,检查该边是否指向堆栈中已有的节点。 这表明循环的存在。 如果找不到这样的边,则该连接组件中不存在循环。
正如 Rutger Prins 指出的那样,如果您的图未连接,则需要对每个连接的组件重复搜索。
作为参考,Tarjan 的强连通分量算法密切相关。 它还将帮助您找到循环,而不仅仅是报告它们是否存在。
Doing a simple depth-first-search is not good enough to find a cycle. It is possible to visit a node multiple times in a DFS without a cycle existing. Depending on where you start, you also might not visit the entire graph.
You can check for cycles in a connected component of a graph as follows. Find a node which has only outgoing edges. If there is no such node, then there is a cycle. Start a DFS at that node. When traversing each edge, check whether the edge points back to a node already on your stack. This indicates the existence of a cycle. If you find no such edge, there are no cycles in that connected component.
As Rutger Prins points out, if your graph is not connected, you need to repeat the search on each connected component.
As a reference, Tarjan's strongly connected component algorithm is closely related. It will also help you find the cycles, not just report whether they exist.
算法简介
(第二版)一书中的引理 22.11 指出:Lemma 22.11 on the Book
Introduction to Algorithms
(Second Edition) states that:方案一:Kahn算法检查循环。 主要思想:维护一个队列,将入度为零的节点添加到队列中。 然后将节点一一剥离,直到队列为空。 检查是否存在任何节点的入边。
解决方案2:Tarjan算法检查强连通分量。
解决方案3:DFS。 使用整数数组来标记节点的当前状态:
即0——表示该节点之前未被访问过。
-1——表示该节点已被访问,并且其子节点正在被访问。
1——表示该节点已被访问,并且已完成。
所以如果一个节点在进行DFS时状态为-1,则说明一定存在环路。
Solution1: Kahn algorithm to check cycle. Main idea: Maintain a queue where node with zero in-degree will be added into queue. Then peel off node one by one until queue is empty. Check if any node's in-edges are existed.
Solution2: Tarjan algorithm to check Strong connected component.
Solution3: DFS. Use integer array to tag current status of node:
i.e. 0 --means this node hasn't been visited before.
-1 -- means this node has been visited, and its children nodes are being visited.
1 -- means this node has been visited, and it's done.
So if a node's status is -1 while doing DFS, it means there must be a cycle existed.
刚刚在谷歌面试中遇到了这个问题。
拓扑排序
你可以尝试拓扑排序,即 O(V + E),其中 V 是顶点数,E 是边数。 当且仅当可以做到这一点时,有向图才是无环的。
递归叶删除
递归地删除叶节点,直到没有剩下的,如果剩下多个节点,则有一个循环。 除非我弄错了,否则这是 O(V^2 + VE)。
DFS 式 ~ O(n + m)
然而,一种高效的 DFS 式算法,最坏情况 O(V + E) 是:
Just had this question in a Google interview.
Topological Sort
You can try to sort topologically, which is O(V + E) where V is the number of vertices, and E is the number of edges. A directed graph is acyclic if and only if this can be done.
Recursive Leaf Removal
The recursively remove leaf nodes until there are none left, and if there's more than a single node left you've got a cycle. Unless I'm mistaken, this is O(V^2 + VE).
DFS-style ~ O(n + m)
However, an efficient DFS-esque algorithm, worst case O(V + E), is:
ShuggyCoUk 给出的解决方案是不完整的,因为它可能没有检查所有节点。
时间复杂度为 O(n+m) 或 O(n^2)
The solution given by ShuggyCoUk is incomplete because it might not check all nodes.
This has timecomplexity O(n+m) or O(n^2)
我知道这是一个老话题,但对于未来的搜索者,这里是我创建的 C# 实现(没有声称它是最有效的!)。 这样做的目的是使用一个简单的整数来标识每个节点。 只要你的节点对象散列和等于正确,你就可以按照你喜欢的方式装饰它。
对于非常深的图,这可能会产生很高的开销,因为它在深度的每个节点上创建一个哈希集(它们在广度上被破坏)。
您输入要搜索的节点以及到达该节点的路径。
当检查低于任何值的循环时给定节点,只需将该节点与空哈希集一起传递
I know this is an old topic but for future searchers here is a C# implementation I created (no claim that it's most efficient!). This is designed to use a simple integer to identify each node. You can decorate that however you like provided your node object hashes and equals properly.
For Very deep graphs this may have high overhead, as it creates a hashset at each node in depth (they are destroyed over breadth).
You input the node from which you want to search and the path take to that node.
When checking for cycles below any given node, just pass that node along with an empty hashset
在做DFS时不应该有任何后边。在做DFS时跟踪已经访问过的节点,如果在当前节点和现有节点之间遇到边,则图有循环。
There should not be any back edge while doing DFS.Keep track of already visited nodes while doing DFS,if you encounter a edge between current node and existing node,then graph has cycle.
这里有一个快速代码来查找图是否有循环:
想法是这样的:一个普通的 dfs 算法,带有一个用于跟踪访问节点的数组,以及一个附加数组,该数组用作导致当前节点的节点的标记节点,这样当我们对节点执行 dfs 时,我们将标记数组中的相应项设置为 true ,这样当遇到已访问过的节点时,我们检查标记数组中其相应项是否为 true ,如果为 true那么它是让自己的节点之一
(因此是一个循环),诀窍是每当节点的 dfs 返回时,我们将其相应的标记设置回 false ,这样,如果我们从另一条路线再次访问它,我们就不会被愚弄。
here is a swift code to find if a graph has cycles :
The idea is like this : a normal dfs algorithm with an array to keep track of visited nodes , and an additional array which serves as a marker for the nodes that led to the current node,so that when ever we execute a dfs for a node we set its corresponding item in the marker array as true ,so that when ever an already visited node encountered we check if its corresponding item in the marker array is true , if its true then its one of the nodes that let to itself
(hence a cycle) , and the trick is whenever a dfs of a node returns we set its corresponding marker back to false , so that if we visited it again from another route we don't get fooled .
这是我的 剥离叶子节点算法的 ruby 实现< /a>.
Here is my ruby implementation of the peel off leaf node algorithm.
这是我的伪代码实现:
Here my implementation in pseudocode:
您可以使用我的答案中的查找循环反转 https://stackoverflow.com/a/60196714/1763149
You can use inversion of finding cycle from my answer here https://stackoverflow.com/a/60196714/1763149