当前位置: 首页 > 知识库问答 >
问题:

在有向图中使用DFS进行循环检测是否绝对需要回溯?

孙宏扬
2023-03-14

我看到了这篇SO帖子,其中建议在有向图中使用DFS进行循环检测由于回溯而更快。这里我引用该链接:

深度优先搜索比广度优先搜索更节省内存,因为您可以更快地回溯。如果使用调用堆栈,则实现起来也更容易,但这取决于不溢出堆栈的最长路径。

如果你的图是有方向的,那么你不仅要记住你是否访问过一个节点,还要记住你是如何到达的。否则,你可能会认为你已经找到了一个循环,但在现实中,你所拥有的只是两条不同的路径-

为什么回溯是必要的?

有人能用示例图解释一下给定A中的含义吗-

最后,我有一个用于有向图中循环检测的DFS代码,它不使用回溯,但仍然在O(E V)中检测循环。

public boolean isCyclicDirected(Vertex v){
  if (v.isVisited) {
    return true;
  }
  v.setVisited(true);
  Iterator<Edge> e = v.adj.iterator();
  while (e.hasNext()) {
    Vertex t = e.next().target;
    // quick test:
    if (t.isVisited) {
      return true;
    }
    // elaborate, recursive test:
    if (isCyclicDirected(t)) {
      return true;
    }
  }
  // none of our adjacent vertices flag as cyclic
  v.setVisited(false);
  return false;
}

共有3个答案

桂嘉年
2023-03-14

只有当您的图没有任何可以通过两条不同路径从节点A到节点B的情况下,回溯才是必要的。你的算法将检测到一个假阳性的情况下,提到在前面的答案:A-

秋光熙
2023-03-14

值得指出的是,这种标记算法是对链表周期检测的朴素方法的一种改进,这种方法涉及到跟踪到目前为止访问的每个节点。在这种情况下,递归后的路径被视为链表,并应用链表算法。对于链表来说,空间复杂度是算法次优的原因,因为您需要保持对列表中每个节点的引用,它是O(n)。然而,当你把它应用到一个相当平衡的图上时,空间复杂度下降到O(logn)。在图是树的情况下,空间复杂度降低为O(n),但时间复杂度为O(n)。

此外,算法仍然不正确。给定一个具有节点aB以及单条边B的图-

於乐
2023-03-14

您需要回溯的原因:

A -> B
^ \
|  v
D <- C

如果你去A-

你的算法会回溯。您只是用递归包装它,所以它可能看起来不太像您期望的那样。你递归为一个邻居,如果这没有找到一个循环,那个调用返回,你尝试其他邻居——这是回溯。

为什么你需要记住你是如何到达现在的位置的:

A -> B
  \  ^
   v |
     C

上图没有循环,但是如果你去A-

正如链接文章中提到的,在返回代码之前,您可以将访问标志设置为false(我看到您现在已经这样做了)——这将起到记住路径的作用。

 类似资料:
  • 另一个问题只回答了如何检测一个周期,而不是输出它。所以,我想在一个无向图上写一个算法,在O(V+E)时间内运行BFS或DFS(V=顶点,E=边),如果有循环,则输出循环。 到目前为止,我所知道的是BFS/DFS是如何工作的,如果访问已经标记为已访问的节点,可以使用BFS检测周期。

  • 因此,我为DFS编写了以下代码: 现在,我读到,在一个无向图中,如果当DFS时,它再次返回到同一个顶点,有一个循环。所以我做的是这样,, 但是,我的检查周期函数返回true,即使他们没有周期。那是为什么呢?我的功能有问题吗?没有执行问题,否则我早就调试了,但他们似乎在我的逻辑中有问题。

  • 我在这里读到一篇关于在有向图中求圈的讨论。现在,OP声称我们需要验证两件事: 从到有一个后沿 在递归堆栈中 为什么我们需要第二次测试?你能举个例子来说明它的必要性吗?

  • 目前我正在用这个样本进行拓扑排序,并对https://www.geeksforgeeks.org/topological-sorting/做了一些修改 我用它来排序要求解的变量的顺序。 样本 每个变量都有一个唯一整数,并存储在一个映射中 创建图形并添加边时,总共有4个顶点,因此我的代码将像这样构造图形 排序并按相反顺序得到结果后,它是正确的c 一切都很好,但我需要检测图中的循环引用。假设变量是 有

  • 我试图用BFS算法在有向图中检测循环。我检测周期的主要想法是:由于BFS只访问每个节点(和边缘)一次,如果我再次遇到已访问的节点;它会导致一个循环。然而,我的代码有时会找到循环,有时不会。 我从维基百科修改的伪代码如下: 我错过了什么?

  • 我有一个带边的无向图。每条边都具有一定的性质,如A点和B点之间的边之一是 在C点和D点之间的另一个可以是 我们得到了这样一个图和已知的旅行路径 有快一点的吗?