如何检测有向图是否包含环?我考虑使用宽度优先搜索,但不确定。您有什么想法吗?
如何检测有向图是否包含环?我考虑使用宽度优先搜索,但不确定。您有什么想法吗?
我相信您真正需要的是像这里描述的拓扑排序算法:
http://en.wikipedia.org/wiki/Topological_sorting
如果有一个循环图,则该算法将失败。
迄今为止我看到的评论/回复似乎忽略了一个事实,在一个定向图中,可能会有多种方法从节点X到达节点Y,而不会在图中存在任何(定向)循环。
class Node<T> { T value; List<Node<T>> adjacent; }
class Graph<T>{
List<Node<T>> nodes;
public boolean isCyclicRec()
{
for (Node<T> node : nodes)
{
Set<Node<T>> initPath = new HashSet<>();
if (isCyclicRec(node, initPath))
{
return true;
}
}
return false;
}
private boolean isCyclicRec(Node<T> currNode, Set<Node<T>> path)
{
if (path.contains(currNode))
{
return true;
}
else
{
path.add(currNode);
for (Node<T> node : currNode.adjacent)
{
if (isCyclicRec(node, path))
{
return true;
}
else
{
path.remove(node);
}
}
}
return false;
}
方法2:
使用3种颜色:白色、灰色和黑色。将只有白色节点的图形全部涂成白色,从DFS开始向下遍历时,将白色节点涂成灰色,当递归展开(所有子节点都被处理)时,将灰色节点涂成黑色。如果还没有处理完所有子节点,而你遇到了一个灰色节点,那么就是一个环。
例如:在上面的有向图中,一开始所有节点都是白色。
A、B、D、F、G节点被涂成白色-灰色。G是叶子节点,所以所有子节点都被处理后,将其涂成灰色-黑色。递归展开到F(所有子节点都被处理),将其涂成黑色。现在到达D,D有未处理的子节点,所以将E涂成灰色。由于G已经被涂成黑色,所以不需要再往下遍历。E也与D相连,因此在处理D(D仍然是灰色)时,找到了一条回到D(一个灰色节点)的边,这就是一个环。
测试给定图的拓扑排序将引导您找到解决方案。如果拓扑排序算法,即边应始终单向指向的规则失败,则意味着该图包含循环。
另一个简单的解决方案是标记-清除法。基本上,对于树中的每个节点,您将其标记为“已访问”,然后继续移动到其子节点。如果您看到一个带有“已访问”标志的节点,则知道存在循环。
如果无法修改图以包括“已访问”位,则可以改用一组节点指针。要将节点标记为已访问,请将指向它的指针放入集合中。如果指针已经在集合中,则存在循环。