5.10
Depth-First Search on Directed Graphs
Depth-first search on an undirected graph proves useful because it organizes the
edges of the graph in a very precise way, as shown in Figure
5.10
.
When traversing undirected graphs, every edge is either in the depth-first search
tree or a back edge to an ancestor in the tree. Let us review why. Suppose we
encountered a “forward edge” (x, y) directed toward a descendant vertex. In this
case, we would have discovered (x, y) while exploring y, making it a back edge.
Suppose we encounter a “cross edge” (x, y), linking two unrelated vertices. Again,
we would have discovered this edge when we explored y, making it a tree edge.
For directed graphs, depth-first search labelings can take on a wider range of
possibilities. Indeed, all four of the edge cases in Figure
5.14
can occur in traversing
directed graphs. Still, this classification proves useful in organizing algorithms on
directed graphs. We typically take a different action on edges from each different
case.
The correct labeling of each edge can be readily determined from the state,
discovery time, and parent of each vertex, as encoded in the following function:
int edge_classification(int x, int y)
{
if (parent[y] == x) return(TREE);
if (discovered[y] && !processed[y]) return(BACK);
if (processed[y] && (entry_time[y]>entry_time[x])) return(FORWARD);
if (processed[y] && (entry_time[y]
printf("Warning: unclassified edge (%d,%d)\n",x,y);
}
5 . 1 0
D E P T H - F I R S T S E A R C H O N D I R E C T E D G R A P H S
179
D
A
G
F
E
C
B
Figure 5.15: A DAG with only one topological sort (G, A, B, C, F, E, D)
As with BFS, this implementation of the depth-first search algorithm includes
places to optionally process each vertex and edge—say to copy them, print them, or
count them. Both algorithms will traverse all edges in the same connected compo-
nent as the starting point. Since we need to start with a vertex in each component
to traverse a disconnected graph, we must start from any vertex remaining undis-
covered after a component search. With the proper initialization, this completes
the traversal algorithm:
DFS-graph(G)
for each vertex u
∈ V [G] do
state[u] = “undiscovered”
for each vertex u
∈ V [ G] do
if state[u] = “undiscovered” then
initialize new component, if desired
DFS(G, u)
I encourage the reader to convince themselves of the correctness of these four
conditions. What I said earlier about the subtlety of depth-first search goes double
for directed graphs.
Do'stlaringiz bilan baham: |