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

使用DFS检测图中的循环:两种不同的方法和区别是什么

韦德厚
2023-03-14

请注意,图表示为邻接列表。

>

  • 保留一个布尔值数组,以跟踪您以前是否访问过节点。如果您没有新的节点可转到(而不是已经转到的节点),那么只需回溯并尝试其他分支。

    来自Cormen的CLRS或Skiena的一个:对于无向图中的深度优先搜索,有两种类型的边,树和背。图有圈当且仅当存在后边。

    谁能解释一下什么是图的后边,以及以上两种方法之间的区别。

    多谢了。

    更新:下面是在这两种情况下检测周期的代码。Graph是一个简单的类,为了简单起见,它将所有的图节点表示为唯一的数字,每个节点都有其相邻的相邻节点(g.getAdmindicentNodes(int)):

    public class Graph {
    
      private int[][] nodes; // all nodes; e.g. int[][] nodes = {{1,2,3}, {3,2,1,5,6}...};
    
      public int[] getAdjacentNodes(int v) {
        return nodes[v];
      }
    
      // number of vertices in a graph
      public int vSize() {
        return nodes.length;
      }
    
    }
    

    检测无向图中的循环的Java代码:

        public class DFSCycle {
    
        private boolean marked[];
        private int s;
        private Graph g;
        private boolean hasCycle;
    
        // s - starting node
        public DFSCycle(Graph g, int s) {
            this.g = g;
            this.s = s;
            marked = new boolean[g.vSize()];
            findCycle(g,s,s);
        }
    
        public boolean hasCycle() {
            return hasCycle;
        }
    
        public void findCycle(Graph g, int v, int u) {
    
            marked[v] = true;
    
            for (int w : g.getAdjacentNodes(v)) {
                if(!marked[w]) {
                    marked[w] = true;
                    findCycle(g,w,v);
                } else if (v != u) {
                    hasCycle = true;
                    return;
                }
            }
    
        }  
    }
    
    public class DFSDirectedCycle {
    
        private boolean marked[];
        private boolean onStack[];
        private int s;
        private Graph g;
        private boolean hasCycle;
    
        public DFSDirectedCycle(Graph g, int s) {
            this.s = s
            this.g = g;
            marked = new boolean[g.vSize()];
            onStack = new boolean[g.vSize()];
            findCycle(g,s);
        }
    
        public boolean hasCycle() {
            return hasCycle;
        }
    
        public void findCycle(Graph g, int v) {
    
            marked[v] = true;
            onStack[v] = true;
    
            for (int w : g.adjacentNodes(v)) {
                if(!marked[w]) {
                    findCycle(g,w);
                } else if (onStack[w]) {
                    hasCycle = true;
                    return;
                }
            }
    
            onStack[v] = false;
        }
    }
    
  • 共有1个答案

    蓝恩
    2023-03-14

    回答我的问题:

    图有圈当且仅当存在后边。后边是从节点到自身(selfloop)或由DFS生成的树中形成循环的一个祖先的边。

    上面的两种方法实际上是相同的。然而,这种方法只能应用于无向图。

    在无向图中求圈

    无向图有圈当且仅当深度优先搜索(DFS)找到指向已访问顶点的边(后边)。

    在有向图中求圈

    除了访问的顶点外,我们还需要跟踪当前DFS遍历的函数递归堆栈中的顶点。如果我们到达一个已经在递归堆栈中的顶点,那么树中就有一个循环

    更新:工作代码在上面的问题部分。

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

    • 我对DFS和回溯算法的区别感到困惑。在我看来,回溯只是一个特殊版本的DFS,对吗?

    • 本文向大家介绍JS中string的startwith和indexof两种方法的区别?相关面试题,主要包含被问及JS中string的startwith和indexof两种方法的区别?时的应答技巧和注意事项,需要的朋友参考一下 参考回答: JS中startwith函数,其参数有3个,stringObj,要搜索的字符串对象,str,搜索的字符串,position,可选,从哪个位置开始搜索,如果以posi

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

    • 我看到了这篇SO帖子,其中建议在有向图中使用DFS进行循环检测由于回溯而更快。这里我引用该链接: 深度优先搜索比广度优先搜索更节省内存,因为您可以更快地回溯。如果使用调用堆栈,则实现起来也更容易,但这取决于不溢出堆栈的最长路径。 如果你的图是有方向的,那么你不仅要记住你是否访问过一个节点,还要记住你是如何到达的。否则,你可能会认为你已经找到了一个循环,但在现实中,你所拥有的只是两条不同的路径- 为

    • 我正在努力学习如何检测循环。我看到很多使用递归的例子,但我想以迭代的方式实现。这是我的密码 它没有按预期工作 我在这里遗漏了什么逻辑?