The Algorithm Design Manual describes BFS and DFS quite well. The code for dfs in the book has a problem when deciding whether or not to avoid double processing edges. I found the Errata and applied the errata to the code, but still I think the refined code has a problem of checking double processing edges.
I paste the refined code as follows:
dfs(graph *g, int v) {
edgenode *p;
int y;
if (finished) return;
discovered[v] = TRUE;
time = time + 1;
entry_time[v] = time;
process_vertex_early(v);
p = g->edges[v];
while (p != NULL) {
/* temporary pointer */
/* successor vertex */
/* allow for search termination */
y = p->y;
if (discovered[y] == FALSE) {
parent[y] = v;
process_edge(v,y);
dfs(g,y);
}
else if (**(!processed[y] && parent[v] != y)** || (g->directed))
process_edge(v,y);
if (finished) return;
p = p->next;
}
process_vertex_late(v);
time = time + 1;
exit_time[v] = time;
processed[v] = TRUE;
}
The place where I think there is a problem is marked via ** **.
So the questionable place is one of the conditions. Let’s assume it is undirected graph, so we can just ignore the condition of (g->directed).
Ok, let’s focus on parent[v] != y first. if parent[v] == y, of course, we don’t need to process edge v->y again because y->v is already processed once when processing vertex y.
And if parent[v] != y, my question is whether !processed[y] && is necessary or not.
So, if y is not v’s parent, and processed[y] == false which means y has been found (otherwise the execution can’t reach else if part) but not been processed, so y must be a grandma or above of v. This is a back edge, but no problem, we can process it as it hasn’t been processed yet.
Now what if processed[y] == true? I think this “if” will never happen and this condition will never be true.
Why? Ok, let’s assume processed[y] can be true. This means that all paths which include y have been processed and also all vertexes in those paths have been processed, right? So if this is a case, how can a “not yet finished processing” vertex v approach y?
I think in dfs, no vertex will ever approach a processed vertex, am I right?
So if we never will meat a processed vertex, we can just remove !processed[y] as it will be always true.
No,
processed[y] == truecould yield true.Look at the following graph, and assume the following [feasible] DFS traversal:
v0starts, and then recursively invokedfs(v1)after processing(v0,v1). Now,v1processes(v1,v2)and recursively invokedfs(v2).v2sees thatv0is discovered and go to theelse ifstatement, and sees that(v0,v2)was not processed andparent[v2] != v0[v2was discovered viav1].Now, when we go back from the recursion we reach back
v0, and when we check the next “son” – it isv2.v2was already discovered, so we go toelse if, andv2is not the parent ofv0, so without the!processed[y]part, we would have processed(v0,v2)twice.The only thing that prevent that from hapenning is the fact that
processed[y] == true