使用DFS检查无向图中的循环

Checking for a cycle in an undirected graph using DFS?

本文关键字:循环 DFS 检查 使用      更新时间:2023-10-16

因此,我为DFS编写了以下代码:

void dfs (graph * mygraph, int foo, bool arr[]) // here, foo is the source vertex
{
    if (arr[foo] == true)
        return;
    else
    {
        cout<<foo<<"t";
        arr[foo] = true;
        auto it = mygraph->edges[foo].begin();
        while (it != mygraph->edges[foo].end())
        {
            int k = *it;
            if (arr[k] == false)
            {
                //cout<<k<<"n";
                dfs(mygraph,k,arr);
                //cout<<k<<"t";
            }
            it++;
        }
    }
    //cout<<"n";
}

现在,我读到在一个无向图中,如果当DFS时,它再次返回到同一个顶点,这是一个循环。因此,我所做的是,

bool checkcycle( graph * mygraph, int foo, bool arr[] )
{
    bool result = false;
    if (arr[foo] == true)
    {
        result = true;
    }
    else
    {
        arr[foo] = true;
        auto it = mygraph->edges[foo].begin();
        while (it != mygraph->edges[foo].end())
        {
            int k = *it;
            result = checkcycle(mygraph,k,arr);     
            it++;
        }
    }
    return result;
}   

但是,我的checkcycle函数返回true,即使他们没有循环。为什么呢?我的功能有问题吗?没有执行问题,否则我就会调试,但他们似乎是我的逻辑有问题。

注意,您的函数并不完全像您想象的那样。让我试着一步一步地解释一下这里发生了什么。假设下列关系:(1,2),(1,3),(2,3)。我没有假设反射性(也就是说,(1,2)并不意味着(2,1))。关系是直接的。

  1. 从节点1开始。标记为已访问
  2. 迭代它的子元素(2和3)
  3. 在节点2时,递归调用check cycle。此时,2也被标记为已访问。
  4. 递归调用现在访问3(深度搜索)。3也被标记为访问
  5. 呼叫步骤4死亡返回false
  6. 呼叫步骤3死亡返回false
  7. 我们回到了第二步。现在我们将迭代节点3,它已经在步骤4中被标记。它只返回true

你需要一个访问节点的堆栈,或者你只搜索原始节点。堆栈也会检测子周期(不包括原始节点的周期),但它也会占用更多的内存。

编辑:节点堆栈不仅仅是一堆true/false值,而是一堆节点号。如果一个节点存在于堆栈中,则在当前堆栈跟踪中访问了该节点。

然而,有一个更内存友好的方法:设置arr[foo] = false;作为调用死亡。像这样:

bool checkcycle( graph * mygraph, int foo, bool arr[], int previousFoo=-1 )
{
    bool result = false;
    if (arr[foo] == true)
    {
        result = true;
    }
    else
    {
        arr[foo] = true;
        auto it = mygraph->edges[foo].begin();
        while (it != mygraph->edges[foo].end())
        {
            int k = *it;
            // This should prevent going back to the previous node
            if (k != previousFoo) {
                result = checkcycle(mygraph,k,arr, foo);
            }
            it++;
        }
        
        // Add this
        arr[foo] = false;
    }
    return result;
}   

我想应该够了。

编辑:现在应该支持无向图。节点:此代码未被测试

编辑:更详细的解决方案请参见强连接组件

编辑:虽然在评论中给出了具体的解决方案,但这个答案是市场所接受的。

在checkcycle开始之前,arr[]中的所有bool都设置为false吗?

你确定你的节点迭代器没有在它已经遍历的边缘上翻倍(因此无论周期如何,都会多次看到起始节点)?