如何使用递归DFS查找图形是否包含循环?

时间:2017-10-19 21:38:39

标签: c algorithm graph-theory

以下代码是深度优先的实现  搜索DFS以确定有向图是否具有循环。然而,它似乎有一个错误,因为它不起作用。我几乎100%确定错误在if (visited[w])条件下。我的逻辑基本上是 - 如果一个节点已被访问过,那么就存在一个循环。然而,if (visited[w])的问题在于虽然条件可能为真,但并不一定意味着存在循环,因为很久以前可能已经访问过该节点。

int *visited;  // array [0..V-1] of booleans

int checkCycle(Graph g)
{
   visited = malloc(sizeof(int)*g->numVertices);
   int result = dfsCycleCheck(g, 0);
   free(visited);
   return result;
}
int dfsCycleCheck(Graph g, Vertex v)
{
   visited[v] = 1;
   Vertex w;
   for (w = 0; w < nV(g); w++) {
      if (!hasEdge(g,v,w)) continue;
      if (visited[w]) return 1; // found cycle
      return dfsCycleCheck(g, w);
   }
   return 0; // no cycle
}

1 个答案:

答案 0 :(得分:1)

您是正确的,无法判断访问过的节点是否已被访问过,或者是否作为当前遍历的一部分被访问过。

一种方法是维护一个可以容纳三种状态的顶点数组,而不是我们已经拥有的两种状态。

  

白色:尚未处理顶点。原来           所有顶点都是白色。

     

灰色:正在处理顶点(DFS)          顶点已经开始,但没有完成,这意味着什么          这个顶点的所有后代(ind DFS树)          尚未处理(或此顶点功能正常          调用堆栈)

     

黑色:顶点及其所有后代都是           处理。

     

在进行DFS时,如果遇到从当前顶点到a的边   GRAY顶点,然后这条边是后边缘,因此有一个循环。

代码将是这样的。

// Recursive function to find if there is back edge
// in DFS subtree tree rooted with 'u'
bool Graph::DFSUtil(int u, int color[])
{
    // GRAY :  This vertex is being processed (DFS
    //         for this vertex has started, but not
    //         ended (or this vertex is in function
    //         call stack)
    color[u] = GRAY;

    // Iterate through all adjacent vertices
    list<int>::iterator i;
    for (i = adj[u].begin(); i != adj[u].end(); ++i)
    {
        int v = *i;  // An adjacent of u

        // If there is
        if (color[v] == GRAY)
          return true;

        // If v is not processed and there is a back
        // edge in subtree rooted with v
        if (color[v] == WHITE && DFSUtil(v, color))
          return true;
    }

    // Mark this vertex as processed
    color[u] = BLACK;

    return false;
}

// Returns true if there is a cycle in graph
bool Graph::isCyclic()
{
    // Initialize color of all vertices as WHITE
    int *color = new int[V];
    for (int i = 0; i < V; i++)
        color[i] = WHITE;

    // Do a DFS traversal beginning with all
    // vertices
    for (int i = 0; i < V; i++)
        if (color[i] == WHITE)
           if (DFSUtil(i, color) == true)
              return true;

    return false;
}

这里的主要区别在于可以访问节点并且仍然是黑色(表示先前访问过该节点)或灰色(表示该节点作为当前遍历的一部分被访问;因此它是后边缘)帮助我们发现我们是否有一个周期。

由于布尔数组,我们之前无法区分这两种类型的访问节点。

Source