简体   繁体   中英

Checking for a cycle in an undirected graph using DFS?

So, I made the following code for 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";
}

Now, I read up that in an undirected graph, if while DFS, it returns to the same vertex again, there is a cycle. Therefore, what I did was this,

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;
}   

But, my checkcycle function returns true even if their is no cycle. Why is that? Is there something wrong with my function? There is no execution problem, otherwise I would have debugged, but their seems to be something wrong in my logic.

Notice that your function doesn't quite do what you think it does. Let me try to step through what's happening here. Assume the following relationships: (1,2), (1,3), (2,3). I'm not assuming reflexibility (that is, (1,2) does not imply (2,1)). Relationships are directed.

  1. Start with node 1. Flag it as visited
  2. Iterate its children (2 and 3)
  3. When in node 2, recursively call check cycle . At this point 2 is also flagged as visited.
  4. The recursive call now visits 3 (DEPTH search). 3 is also flagged as visited
  5. Call for step 4 dies returning false
  6. Call for step 3 dies returning false
  7. We're back at step 2. Now we'll iterate node 3, which has already been flagged in step 4. It just returns true .

You need a stack of visited nodes or you ONLY search for the original node. The stack will detect sub-cycles as well (cycles that do not include the original node), but it also takes more memory.

Edit: the stack of nodes is not just a bunch of true / false values, but instead a stack of node numbers. A node has been visited in the current stack trace if it's present in the stack.

However, there's a more memory-friendly way: set arr[foo] = false; as the calls die. Something like this:

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;
}   

I think it should be enough.

Edit: should now support undirected graphs. Node: this code is not tested

Edit: for more elaborate solutions see Strongly Connected Components

Edit: this answer is market as accepted although the concrete solution was given in the comments. Read the comments for details.

are all of the bools in arr[] set to false before checkcycle begins?

are you sure your iterator for the nodes isn't doubling back on edges it has already traversed (and thus seeing the starting node multiple times regardless of cycles)?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM