以下代码是深度优先的实现
搜索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
}
答案 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; }
这里的主要区别在于可以访问节点并且仍然是黑色(表示先前访问过该节点)或灰色(表示该节点作为当前遍历的一部分被访问;因此它是后边缘)帮助我们发现我们是否有一个周期。
由于布尔数组,我们之前无法区分这两种类型的访问节点。