Depth-First Search and Linear Graph Algorithms

About this paperTiếng Việt中文日本語beside Tiếng Việtbeside 中文beside 日本語

This paper is under a licence that does not allow it to be reproduced, so what is here is its front matter and a short abstract. Read it at the publisher's page.

Robert Tarjan†

Abstract. The value of depth-first search or “backtracking” as a technique for solving problems is illustrated by two examples. An improved version of an algorithm for finding the strongly connected components of a directed graph and an algorithm for finding the biconnected components of an undirect graph are presented. The space and time requirements of both algorithms are bounded by k1V+k2E+k3k_1 V + k_2 E + k_3 for some constants k1,k2,k_1, k_2, and k3k_3, where VV is the number of vertices and EE is the number of edges of the graph being examined.

Key words. Algorithm, backtracking, biconnectivity, connectivity, depth-first, graph, search, spanning tree, strong-connectivity.

  1. Introduction. Consider a graph GG, consisting of a set of vertices V\mathcal{V} and a set of edges E\mathcal{E}. The graph may either be directed (the edges are ordered pairs (v,w)(v, w) of vertices; vv is the tail and ww is the head of the edge) or undirected (the edges are unordered pairs of vertices, also represented as (v,w)(v, w)). Graphs form a suitable abstraction for problems in many areas; chemistry, electrical engineering, and sociology, for example. Thus it is important to have the most economical algorithms for answering graph-theoretical questions.

In studying graph algorithms we cannot avoid at least a few definitions. These definitions are more-or-less standard in the literature. (See Harary [3], for instance.) If G=(V,E)G = (\mathcal{V}, \mathcal{E}) is a graph, a path p:v⇒∗wp : v \Rightarrow^* w in GG is a sequence of vertices and edges leading from vv to ww. A path is simple if all its vertices are distinct. A path p:v⇒∗vp : v \Rightarrow^* v is called a closed path. A closed path p:v⇒∗vp : v \Rightarrow^* v is a cycle if all its edges are distinct and the only vertex to occur twice in pp is vv, which occurs exactly twice. Two cycles which are cyclic permutations of each other are considered to be the same cycle. The undirected version of a directed graph is the graph formed by converting each edge of the directed graph into an undirected edge and removing duplicate edges. An undirected graph is connected if there is a path between every pair of vertices.

A (directed rooted) tree TT is a directed graph whose undirected version is connected, having one vertex which is the head of no edges (called the root), and such that all vertices except the root are the head of exactly one edge. The relation “(v,w)(v, w) is an edge of TT” is denoted by v→wv \rightarrow w. The relation “There is a path from vv to ww in TT” is denoted by v⇒∗wv \Rightarrow^* w. If v→wv \rightarrow w, vv is the father of ww and ww is a son of vv. If v⇒∗wv \Rightarrow^* w, vv is an ancestor of ww and ww is a descendant of vv. Every vertex is an ancestor and a descendant of itself. If vv is a vertex in a tree TT, TvT_v is the subtree of TT having as vertices all the descendants of vv in TT. If GG is a directed graph, a tree TT is a spanning tree of GG if TT is a subgraph of GG and TT contains all the vertices of GG.

If RR and SS are binary relations, R∗R^* is the transitive closure of RR, R−1R^{-1} is the inverse of RR, and

RS={(u,w)∣∃v((u,v)∈R&(v,w)∈S)}.RS = \{(u, w) | \exists v((u, v) \in R \& (v, w) \in S)\}.

* Received by the editors August 30, 1971, and in revised form March 9, 1972. † Department of Computer Science, Cornell University, Ithaca, New York 14850. This research was supported by the Hertz Foundation and the National Science Foundation under Grant GJ-992.

If f,f1,⋯ ,fnf, f_1, \cdots, f_n are functions of x1,⋯ ,xnx_1, \cdots, x_n, we say ff is O(f1,⋯ ,fn)O(f_1, \cdots, f_n) if

∣f(x1,⋯ ,xn)∣≤k0+k1∣f1(x1,⋯ ,xn)∣+⋯+kn∣fn(x1,⋯ ,xn)∣|f(x_1, \cdots, x_n)| \leq k_0 + k_1|f_1(x_1, \cdots, x_n)| + \cdots + k_n|f_n(x_1, \cdots, x_n)|

for all xix_i and some constants k0,⋯ ,knk_0, \cdots, k_n. We shall assume a random-access computer model.

  1. Depth-first search. Backtracking, or depth-first search, is a technique which has been widely used for finding solutions to problems in combinatorial theory and artificial intelligence [2], [11] but whose properties have not been widely analyzed. Suppose GG is a graph which we wish to explore. Initially all the vertices of GG are unexplored. We start from some vertex of GG and choose an edge to follow. Traversing the edge leads to a new vertex. We continue in this way; at each step we select an unexplored edge leading from a vertex already reached and we traverse this edge. The edge leads to some vertex, either new or already reached. Whenever we run out of edges leading from old vertices, we choose some unreached vertex, if any exists, and begin a new exploration from this point. Eventually we will traverse all the edges of GG, each exactly once. Such a process is called a search of GG.

There are many ways of searching a graph, depending upon the way in which edges to search are selected. Consider the following choice rule: when selecting an edge to traverse, always choose an edge emanating from the vertex most recently reached which still has unexplored edges. A search which uses this rule is called a depth-first search. The set of old vertices with possibly unexplored edges may be stored on a stack. Thus a depth-first search is very easy to program either iteratively or recursively, provided we have a suitable computer representation of a graph.

Definition 1. Let G=(V,E)G = (\mathcal{V}, \mathcal{E}) be a graph. For each vertex v∈Vv \in \mathcal{V} we may construct a list containing all vertices ww such that (v,w)∈E(v, w) \in \mathcal{E}. Such a list is called an adjacency list for vertex vv. A set of such lists, one for each vertex in GG, is called an adjacency structure for GG.

If the graph GG is undirected, each edge (v,w)(v, w) is represented twice in an adjacency structure; once for vv and once for ww. If GG is directed, each edge (v,w)(v, w) is represented once: vertex ww appears in the adjacency list of vertex vv. A single graph may have many adjacency structures; in fact, each ordering of the edges around the vertices of GG gives a unique adjacency structure, and each adjacency structure corresponds to a unique ordering of the edges at each vertex. Using an adjacency structure for a graph, we can perform depth-first searches in a very efficient manner, as we shall see.

Suppose GG is a connected undirected graph. A search of GG imposes a direction on each edge of GG given by the direction in which the edge is traversed when the search is performed. Thus GG is converted into a directed graph G′G'. The set of edges which lead to a new vertex when traversed during the search defines a spanning tree of G′G'. In general, the arcs of G′G' which are not part of the spanning tree interconnect the paths in the tree. However, if the search is depth-first, each edge (v,w)(v, w) not in the spanning tree connects vertex vv with one of its ancestors ww.

Definition 2. Let PP be a directed graph, consisting of two disjoint sets of edges, denoted by v→wv \to w and v⟶wv \longrightarrow w respectively. Suppose PP satisfies the following properties: {#tarjan-1972-dfs-def-2 .statement tag=03E4} (i) The subgraph TT containing the edges v→wv \to w is a spanning tree of PP.

(ii) We have −→⊆(→∗)−1-\rightarrow \subseteq (\rightarrow^*)^{-1}, where “→\rightarrow” and “−→-\rightarrow” denote the relations defined by the corresponding set of edges. That is, each edge which is not in the spanning tree TT of PP connects a vertex with one of its ancestors in TT. Then PP is called a palm tree. The edges v→wv \rightarrow w are called the fronds of PP.

Theorem 1. Let PP be the directed graph generated by a depth-first search of a connected graph GG. Then PP is a palm tree. Conversely, let PP be any palm tree. Then PP is generated by some depth-first search of the undirected version of PP.

Proof. Consider the program listed below, which carries out a depth-first search of a connected graph, starting at vertex ss, using an adjacency structure of the graph to be searched. The program numbers the vertices of the graph in the order they are reached during the search and constructs the directed graph (P)(P) generated by the search.

            
              BEGIN
INTEGER i;
PROCEDURE DFS(v, u); COMMENT vertex u is the father of vertex v in the spanning tree being constructed;
BEGIN
NUMBER (v) := i := i + 1;
FOR w in the adjacency list of v DO
BEGIN
IF w is not yet numbered THEN
BEGIN
construct arc v → w in P;
DFS(w, v);
END
ELSE IF NUMBER (w) < NUMBER (v) and w → = u THEN construct arc v → w in p;
END;
i := 0;
DFS(s, 0);
END;
            
          

Figure 1 gives an example of the application of DFS to a graph. Suppose P=(V,E)P = (\mathcal{V}, \mathcal{E}) is the directed graph generated by a depth-first search of some connected graph GG, and assume that the search begins at vertex ss. Examine the procedure DFS. The algorithm clearly terminates because each vertex can only be numbered once. Furthermore, each edge in the graph is examined exactly twice. Therefore the time required by the search is linear in VV and EE.

For any vertices vv and ww, let d(v,w)d(v, w) be the length of the shortest path between vv and ww in GG. Since GG is connected, all distances are finite. Suppose that some vertex remains unnumbered by the search. Let vv be an unnumbered vertex such that d(s,v)d(s, v) is minimal. Then there is a vertex ww such that ww is adjacent to vv and d(s,w)<d(s,v)d(s, w) < d(s, v). Thus ww is numbered. But vv will also be numbered, since it is adjacent to ww. This means that all vertices are numbered during the search.

Figure 1
Application of depth-first search to a graph

(a) The graph (b) Order of edge exploration (c) Generated palm tree, with numbers of vertices in ( )

The vertex s is the head of no edge w → s. Each other vertex v is the head of exactly one edge w → v. The subgraph T of P defined by the edges v → w is obviously connected. Thus T is a spanning tree of P.

Each arc of the original graph is directed in at least one direction; if (v, w) does not become an arc of the spanning tree T, either v → w or w → v must be constructed since both v and w are numbered whenever edge (v, w) is inspected and either NUMBER (v) < NUMBER (w) or NUMBER (v) > NUMBER (w).

The arcs v → w run from smaller numbered points to larger numbered points. The arcs v → w run from larger numbered points to smaller numbered points. If arc v → w is constructed, arc w → v is not constructed later because v is numbered. If arc w → v is constructed, arc v → w is not later constructed, because of the test “w — = u” in procedure DFS. Thus each edge in the original graph is directed in one and only one direction.

Consider an arc v → w. We have NUMBER (w) < NUMBER (v). Thus w is numbered before v. Since v → w is constructed and not w → v, v must be numbered before edge (w, v) is inspected. Thus v must be numbered during execution of DFS (w,−)(w, -). But all vertices numbered during execution of DFS (w,−)(w, -) are descendants of ww. This means that w→∗vw \rightarrow^* v, and GG is a palm tree.

Let us prove the converse part of the theorem. Suppose that PP is a palm tree, with spanning tree TT and undirected version GG. Construct an adjacency structure of GG in which all the edges of TT appear before the other edges of GG in the adjacency lists. Starting with the root of TT, perform a depth-first search using this adjacency structure. The search will traverse the edges of TT preferentially and will generate the palm tree PP; it is easy to see that each edge is directed correctly. This completes the proof of the theorem.

We may state Theorem 1 nonconstructively as the following corollary.

Corollary 2. Let GG be any undirected graph. Then GG can be converted into a palm tree by directing its edges in a suitable manner.

  1. Biconnectivity. The value of depth-first search follows from the simple structure of a palm tree. Let us consider a problem in which this structure is useful.

Definition 3. Let G=(V,E)G = (\mathcal{V}, \mathcal{E}) be an undirected graph. Suppose that for each triple of distinct vertices v,w,av, w, a in V\mathcal{V}, there is a path p:v⇒∗wp : v \Rightarrow^* w such that aa is not on the path pp. Then GG is biconnected. (Other equivalent definitions of biconnectedness exist.) If, on the other hand, there is a triple of distinct vertices v,w,av, w, a in V\mathcal{V} such that aa is on any path p:v⇒∗wp : v \Rightarrow^* w, and there exists at least one such path, then aa is called an articulation point of GG.

Lemma 3. Let G=(V,E)G = (\mathcal{V}, \mathcal{E}) be an undirected graph. We may define an equivalence relation on the set of edges as follows: two edges are equivalent if and only if they belong to a common cycle. Let the distinct equivalence classes under this relation be Ei,1≤i≤n\mathcal{E}_i, 1 \leq i \leq n, and let Gi=(Vi,Ei)G_i = (\mathcal{V}_i, \mathcal{E}_i), where Vi\mathcal{V}_i is the set of vertices incident to the edges of Ei\mathcal{E}_i; Vi={v∣∃w((v,w)∈Ei)}\mathcal{V}_i = \{v | \exists w ((v, w) \in \mathcal{E}_i)\}. Then: {#tarjan-1972-dfs-lem-3 .statement tag=03E9} (i) GiG_i is biconnected, for each 1≤i≤n1 \leq i \leq n. (ii) No GiG_i is a proper subgraph of a biconnected subgraph of GG. (iii) Each articulation point of GG occurs more than once among the Vi,1≤i≤n\mathcal{V}_i, 1 \leq i \leq n. Each nonarticulation point of GG occurs exactly once among the Vi,1≤i≤n\mathcal{V}_i, 1 \leq i \leq n. (iv) The set Vi∩Vj\mathcal{V}_i \cap \mathcal{V}_j contains at most one point, for any 1≤i,j≤n1 \leq i, j \leq n. Such a point of intersection is an articulation point of the graph.

The subgraphs GiG_i of GG are called the biconnected components of GG.

Suppose we wish to determine the biconnected components of an undirected graph GG. Common algorithms for this purpose, for instance, Shirey's [14], test each vertex in turn to discover if it is an articulation point. Such algorithms require time proportional to V⋅EV \cdot E, where VV is the number of vertices and EE is the number of edges of the graph. A more efficient algorithm uses depth-first search. Let PP be a palm tree generated by a depth-first search. Suppose the vertices of PP are numbered in the order they are reached during the search (as is done by the procedure DFS above). We shall refer to vertices by their numbers. If uu is an ancestor of vv in the spanning tree TT of PP, then u<vu < v. For any vertex vv in PP, let LOWPT (v)(v) be the smallest vertex in the set {v}∪{w∣v→∗→w}\{v\} \cup \{w | v \rightarrow^* \rightarrow w\}. That is, LOWPT (v)(v) is the smallest vertex reachable from vv by traversing zero or more tree arcs followed by at most one frond. The following results form the basis of an efficient algorithm for finding biconnected components. This algorithm was discovered by Hopcroft and Tarjan [4]. Paton [12] describes a similar algorithm.

Lemma 4. Let G be an undirected graph and let P be a palm tree formed by directing the edges of G. Let T be the spanning tree of P. Suppose p : v ⇒∗\Rightarrow * w is any path in G. Then p contains a point which is an ancestor of both v and w in T.

Proof. Let TuT_u with root u be the smallest subtree of T containing all vertices on the path p. If u=vu = v or u=wu = w, the lemma is immediate. Otherwise, let Tu1T_{u_1} and Tu2T_{u_2} be two distinct subtrees containing points on p such that u→u1u \rightarrow u_1 and u→u2u \rightarrow u_2. If only one such subtree exists, then u is on p since TuT_u is minimal. If two such subtrees exist, path p can only get from Tu1T_{u_1} to Tu2T_{u_2} by passing through vertex u, since no point in one of these trees is an ancestor of any point in the other, while both →\rightarrow and ⟶\longrightarrow connect only ancestors in a palm tree. Since u is an ancestor of both v and w, the lemma holds.

Lemma 5. Let G be a connected undirected graph. Let P be a palm tree formed by directing the edges of G, and let T be the spanning tree of P. Suppose a, v, w are distinct vertices of G such that (a,v)∈T(a, v) \in T, and suppose w is not a descendant of v in T. (That is, ¬(v⇒∗w)\neg (v \Rightarrow * w) in T.) If LOWPT(v)≥a\mathrm{LOWPT}(v) \geq a, then a is an articulation point of P and removal of a disconnects v and w. Conversely, if a is an articulation point of G, then there exist vertices v and w which satisfy the properties above.

Proof. If a→va \rightarrow v and LOWPT(v)≥a\mathrm{LOWPT}(v) \geq a, then any path from v not passing through a remains in the subtree TvT_v, and this subtree does not contain the point w. This gives the first part of the lemma.

To prove the converse, let a be an articulation point of G. If a is the root of P, then at least two tree arcs must emanate from a. Let v be the head of one such arc and let w be the head of another such arc. Then a→va \rightarrow v, LOWPT(v)≥a\mathrm{LOWPT}(v) \geq a, and w is not a descendant of v. If a is not the root of P, consider the connected components formed by deleting a from G. One component must consist only of descendants of a. Such a component can contain only one son of v by Lemma 4. Let v be such a son of a. Let w be any proper ancestor of a. Then a→va \rightarrow v, LOWPT(v)≥a\mathrm{LOWPT}(v) \geq a, and w is not a descendant of v. Thus the converse part of the lemma is true.

Corollary 6. Let G be a connected undirected graph, and let P be a palm tree formed by directing the edges of G. Suppose that P has a spanning tree T. If C is a biconnected component of G, then the vertices of C define a subtree of T, and the root of this subtree is either an articulation point of G or is the root of T.

Figure 2 shows a graph, its LOWPT values, articulation points, and biconnected components. The LOWPT values of all the vertices of a palm tree P may be calculated during a single depth-first search, since

LOWPT(v)=min⁡({NUMBER(v)}∪{LOWPT(w)∣v→w}\mathrm{LOWPT}(v) = \min (\{\mathrm{NUMBER}(v)\} \cup \{\mathrm{LOWPT}(w)|v \rightarrow w\}
∪{NUMBER(w)∣v⟶w}).\cup \{\mathrm{NUMBER}(w)|v \longrightarrow w\}).

On the basis of such a calculation, the articulation points and the biconnected components may be determined, all during one search. The biconnectivity algorithm is presented below. The program will compute the biconnected components

Figure 2
A graph and its biconnected components*

(a) Graph (b) A palm tree with LOWPT values in [ ], articulation points marked with * (c) Biconnected components of a graph GG, starting from vertex ss.

            
              BEGIN
    INTEGER i;
    procedure BICONNECT (v, u);
        BEGIN
            NUMBER (v) := i := i + 1;
            LOWPT (v) = NUMBER (v);
            FOR w in the adjacency list of v DO
                BEGIN
                    IF w is not yet numbered THEN
                        BEGIN
                            add (v, w) to stack of edges;
                            BICONNECT (w, v)
                            LOWPT (v) := min (LOWPT (v), LOWPT (w));
                            IF LOWPT (w) ≥ NUMBER (v) THEN
                                BEGIN
                                    start new biconnected component;
                                    WHILE top edge e = (u₁, u₂) on edge stack has NUMBER (u₁) ≥ NUMBER (w) DO
                                        delete (u₁, u₂) from edge stack and add it to current component;
                                        delete (v, w) from edge stack and add it to current component;
                                END;
                        END
                    ELSE IF (NUMBER (w) < NUMBER (v)) and (w → = u) THEN
                        BEGIN
                            add (v, w) to edge stack;
                            LOWPT (v) := min (LOWPT (v), NUMBER (w));
                        END;
                END;
            END;
        END;
    i := 0;
    empty the edge stack;
    FOR w a vertex DO IF w is not yet numbered THEN BICONNECT (w, 0);
END;
            
          

The edges of GG are placed on a stack as they are traversed; when an articulation point is found the corresponding edges are all on top of the stack. (If (v,w)∈T(v, w) \in T and LOWPT(w)≥LOWPT(v)\mathrm{LOWPT}(w) \geq \mathrm{LOWPT}(v), then the corresponding biconnected component contains the edges in {(u1,u2)∣w→∗u1}∪{(v,w)}\{(u_1, u_2)|w \rightarrow^* u_1\} \cup \{(v, w)\} which are on the edge stack.) A single search on each connected component of a graph GG will give us all the connected components of GG.

THEOREM 7. The biconnectivity algorithm requires O(V,E)O(V, E) space and time when applied to a graph with VV vertices and EE edges.

Proof. The algorithm clearly requires space bounded by k1V+k2E+k3k_1 V + k_2 E + k_3, for some constants k1,k2,k_1, k_2, and k3k_3. The algorithm is an elaboration of the depth-first search procedure DFS. During the search, LOWPT values are calculated and each edge is placed on the edge stack once and removed from the edge stack once. The amount of extra time required by these operations is proportional to EE. Thus BICONNECT has a time bound linear in VV and EE.

Theorem 8. The biconnectivity algorithm correctly gives the biconnected components of any undirected graph G.

Proof. The actual depth-first search undertaken by the algorithm depends on the adjacency structure chosen to represent GG; we shall prove that the algorithm is correct for all adjacency structures. Notice first that the biconnectivity algorithm analyzes each connected component of GG separately to find its biconnected components, applying one depth-first search to each connected component. Thus we need only prove that the biconnectivity algorithm works correctly on connected graphs GG.

The correctness proof is by induction on the number of edges in GG. Suppose GG is connected and contains no edges. GG either is empty or consists of a single point. The algorithm will terminate after examining GG and listing no components. Thus the algorithm operates correctly in this case. Now suppose that the algorithm works correctly on all connected graphs with E−1E - 1 or fewer edges. Consider applying the algorithm to a connected graph GG with EE edges.

Each edge placed on the stack of edges is eventually removed and added to a component since everything on the edge stack is removed whenever the search returns to the root of the palm tree of GG. Consider the situation when the first component G′G' is formed. Suppose that this component does not include all the edges of GG. Then the vertex vv currently being examined is an articulation point of the graph and separates the edges in the component from the other edges in the graph by Lemma 5.

Consider only the set of edges in the component. If BICONNECT (v,0)(v, 0) is executed, using the graph G′G' as data, the steps taken by the algorithm are the same as those taken during the analysis of the edges of G′G' when the data consists of the entire graph GG. Since G′G' contains fewer edges than GG, the algorithm operates correctly on G′G' and G′G' must be biconnected. If we delete the edges of G′G' from GG, we get another subgraph G′′G'' with fewer edges than GG since G′G' is not empty. The algorithm operates correctly on G′′G'' by the induction assumption. The behavior of the algorithm on GG is simply a composite of its behavior on G′G' and on G′′G''; thus the algorithm must operate correctly on GG.

Now suppose that only one component is found. We want to show that in this case GG is biconnected. Suppose that GG is not biconnected. Then GG has an articulation point aa. By Lemma 5, LOWPT (v)≥a(v) \geq a for some son vv of aa. But the articulation point test in the program will succeed when the edge (a,v)(a, v) is examined, and more than one biconnected component will be generated. This contradiction shows that GG is biconnected, and the algorithm works correctly in this case.

By induction, the biconnectivity algorithm gives the correct components when applied to any connected graph, and hence when applied to any graph.

  1. Strong connectivity. The biconnectivity algorithm shows how useful depth-first search can be when applied to undirected graphs. However, when a directed graph is searched in a depth-first manner, a simple palm tree structure does not result, because the direction of search on each edge is fixed. The more complicated structure which results in this case is still simple enough to prove useful in at least one application.

Definition 4. Let G be a directed graph. Suppose that for each pair of vertices v, w in G, there exist paths p1:v⇒∗wp_1 : v \Rightarrow^* w and p2:w⇒∗vp_2 : w \Rightarrow^* v. Then G is said to be strongly connected.

Lemma 9. *Let G=(V,E)G = (\mathcal{V}, \mathcal{E}) be a directed graph. We may define an equivalence relation on the set of vertices as follows: two vertices v and w are equivalent if there is a closed path p:v⇒∗vp : v \Rightarrow^* v which contains w. Let the distinct equivalence classes under this relation be Vi,1≤i≤n\mathcal{V}_i, 1 \leq i \leq n. Let Gi=(Vi,Ei)G_i = (\mathcal{V}_i, \mathcal{E}_i), where Ei={(v,w)∈E∣v,w∈Vi}\mathcal{E}_i = \{(v, w) \in \mathcal{E} | v, w \in \mathcal{V}_i\}. Then:

(i) Each GiG_i is strongly connected. (ii) No GiG_i is a proper subgraph of a strongly connected subgraph of G.*

The subgraphs GiG_i are called the strongly connected components of G.

Suppose we wish to determine the strongly connected components of a directed graph. This problem is related to the problem of determining the ergodic subchains and transient states of a Markov chain. Fox and Landy [1] give an algorithm for solving the latter problem; Purdom [13] and Munro [10] present virtually identical methods for solving the former problem. These algorithms use depth-first search. Purdom claims a time bound of kV2k V^2 for his algorithm; Munro claims kmax⁡(E,Vlog⁡V)k \max (E, V \log V), where the graph has VV vertices and EE edges. Their algorithm attempts to construct a cycle by starting from a point and beginning a depth-first search. When a cycle is found, the vertices on the cycle are marked as being in the same strongly connected component and the process is repeated. The algorithm has the disadvantage that two small strongly connected components may be collapsed into a bigger one; the resultant extra work in relabeling may contribute V2V^2 steps using a simple approach, or Vlog⁡VV \log V steps if a more sophisticated approach is used (see Munro [10]). In fact, the time bound may be reduced further if an efficient list merging algorithm [9] is used. However, a more careful study of what a depth-first search does to a directed graph reveals that an O(V,E)O(V, E) algorithm which requires no merging of components may be devised.

Consider what happens when a depth-first search is performed on a directed graph GG. The set of edges which lead to a new vertex when traversed during the search form a tree. The other edges fall into three classes. Some are edges running from ancestors to descendants in the tree. These edges may be ignored, because they do not affect the strongly connected components of GG. Some edges run from descendants to ancestors in the tree; these we may call fronds as above. Other edges run from one subtree to another in the tree. These, we call cross-links. It is easy to verify that if the vertices of the tree are numbered in the order they are reached during the search, a cross-link (v,w)(v, w) always has NUMBER(v)>NUMBER(w)\mathrm{NUMBER}(v) > \mathrm{NUMBER}(w). We shall denote tree edges by v→wv \rightarrow w, and fronds and cross-links by v→wv \rightarrow w.

Suppose GG is a directed graph, to which a depth-first search algorithm is applied repeatedly until all the edges are explored. The process will create a set of trees which contain all the vertices of GG, called the spanning forest FF of GG, and sets of fronds and cross-links. (Other edges are thrown away.) A directed graph consisting of a spanning forest and sets of fronds and cross-links is called a jungle. Suppose the vertices are numbered in the order they are reached during the search and that we refer to vertices by their number. Then we have the following results.

Lemma 10. Let v and w be vertices in G which lie in the same strongly connected component. Let F be a spanning forest of G generated by repeated depth-first search. Then v and w have a common ancestor in F. Further, if u is the highest numbered common ancestor of v and w, then u lies in the same strongly connected component as v and w.

Proof. Without loss of generality we may assume v≤wv \leq w. Let p be a path from v to w in G. Let TuT_u with root u be the smallest subtree of a tree in F containing all the vertices in p. There must be such a tree, since p can pass from one tree in F to another tree with smaller numbered vertices but p can never lead to a tree with larger numbered vertices. If p were contained in two or more trees of F, it could not end at w, since v≤wv \leq w.

Thus TuT_u exists, and v and w have a common ancestor in F. In fact, p must pass through vertex u, by a proof similar to the proof of Lemma 4, and u, v, w must all be in the same strongly connected component. This gives the lemma.

Corollary 11. Let C be a strongly connected component in G. Then the vertices of C define a subtree of a tree in F, the spanning forest of G. The root of this subtree is called the root of the strongly connected component C.

The problem of finding the strongly connected components of a graph G thus reduces to the problem of finding the roots of the strongly connected components, just as the problem of finding the biconnected components of an undirected graph reduces to the problem of finding the articulation points of the graph. We can construct a simple test to determine if a vertex is the root of a strongly connected component. Let

LOWLINK(v)=min⁡({v}∪{w∣v→∗w∧∃u(u→∗v∧u→∗w∧u and w are in the same strongly connected component of G})\text{LOWLINK}(v) = \min(\{v\} \cup \{w|v \stackrel{*}{\rightarrow} w \land \exists u (u \stackrel{*}{\rightarrow} v \land u \stackrel{*}{\rightarrow} w \land u \text{ and } w \text{ are in the same strongly connected component of } G\})

That is, LOWLINK (v)(v) is the smallest vertex which is in the same component as vv and is reachable by traversing zero or more tree arcs followed by at most one frond or cross-link.

Lemma 12. Let G be a directed graph with LOWLINK defined as above relative to some spanning forest F of G generated by depth-first search. Then v is the root of some strongly connected component of G if and only if LOWLINK(v)=v\text{LOWLINK}(v) = v.

Proof. Obviously, if v is the root of a strongly connected component C of G, then LOWLINK(v)=v\text{LOWLINK}(v) = v, since if LOWLINK(v)<v\text{LOWLINK}(v) < v, some proper ancestor of v would be in C and v could not be the root of C.

Consider the converse. Suppose u is the root of a strongly connected component C of G, and v is a vertex in C different from u. There must be a path p:v⇒∗up : v \stackrel{*}{\Rightarrow} u. Consider the first edge on this path which leads to a vertex w not in the subtree TvT_v. This edge is either a vine or a cross-link, and we must have LOWLINK(v)≤w<v\text{LOWLINK}(v) \leq w < v, since the highest numbered common ancestor of v and w is in C.

Figure 3 shows a directed graph, its LOWLINK values, and its strongly connected components. LOWLINK may be calculated using depth-first search.

An algorithm for computing the strongly connected components of a directed graph in O(V,E)O(V, E) time may be based on such a calculation. An implementation of such an algorithm is presented below. The points which have been reached during the search but which have not yet been placed in a component are stored on a stack. This stack is analogous to the stack of edges used by the biconnectivity algorithm.

            
              BEGIN
    INTEGER i;
    PROCEDURE STRONGCONNECT (v);
        BEGIN
            LOWLINK (v) := NUMBER (v) := i := i + 1;
            put v on stack of points;
            FOR w in the adjacency list of v DO
                BEGIN
                    IF w is not yet numbered THEN
                        BEGIN comment (v, w) is a tree arc;
                            STRONGCONNECT (w);
                            LOWLINK (v) := min (LOWLINK (v), LOWLINK (w));
                        END
                    ELSE IF NUMBER (w) < NUMBER (v) DO
                        BEGIN comment (v, w) is a frond or cross-link;
                            if w is on stack of points THEN
                                LOWLINK (v) := min (LOWLINK (v), NUMBER (w));
                        END;
                END;
            If (LOWLINK (v) = NUMBER (v)) THEN
                BEGIN comment v is the root of a component;
                    start new strongly connected component;
                    WHILE w on top of point stack satisfies
                        NUMBER (w) ≥ NUMBER (v) DO
                        delete w from point stack and put w in current component;
                END;
            END;
            i := 0;
            empty stack of points;
            FOR w a vertex IF w is not yet numbered THEN STRONGCONNECT (w);
        END;
    END;
            
          

THEOREM 13. The algorithm for finding strongly connected components requires O(V,E)O(V, E) space and time. Proof. The algorithm clearly requires space bounded by k1V+k2E+k3k_1 V + k_2 E + k_3, for some constants k1,k2,k_1, k_2, and k3k_3. The algorithm is an elaboration of the depth-first search procedure DFS, modified to apply to directed graphs. During the search, LOWLINK values are calculated, each point is placed on the stack of

Figure 3
A graph and its strongly connected components*

(a) Graph (b) Jungle generated by depth-first search with LOWLINK values in [ ], roots of components marked with * (c) Strongly connected components points once, and each point is removed from the stack of points once. Testing to see if a vertex is on the point stack can be done in a fixed time if a Boolean array is kept which answers this question for each vertex. The amount of extra time required by these operations is linear in VV and EE. Thus STRONGCONNECT has a time bound linear in VV and EE.

Theorem 14. The algorithm for finding strongly connected components works correctly on any directed graph G.

Proof. We prove by induction that the calculation of LOWLINK (vv) is correct. Suppose as the induction hypothesis that for all vertices vv such that vv is a proper descendant of vertex kk or v<kv < k, LOWLINK (vv) is computed correctly. This means that the test to determine if vv is the root of a component is performed correctly for all such vertices vv. The reader may verify that this somewhat strange induction hypothesis corresponds to considering vertices in the order they are examined for the last time during the depth-first search process.

Consider vertex v=kv = k. Let v→∗w1v \rightarrow^* w_1 and let w1→w2w_1 \rightarrow w_2 be a vine or cross-link such that w2<vw_2 < v. If vertices vv and w2w_2 have no common ancestor, then before vertex vv is reached during the search, vertex w2w_2 must have been removed from the stack of points and placed in a component. (The smallest numbered ancestor of vertex w2w_2 must be a component root.) Thus edge w1→w2w_1 \rightarrow w_2 does not enter into the calculation of LOWLINK (vv).

Otherwise, let uu be the highest common ancestor of vv and w2w_2. Vertex vv is also the highest common ancestor of w1w_1 and w2w_2. If uu is not in the same strongly connected component as w2w_2, then there must be a strongly connected component root on the tree path u→∗w2u \rightarrow^* w_2. Since w2<vw_2 < v, this root was discovered and w2w_2 was removed from the stack of points and placed in a component before the edge w1→w2w_1 \rightarrow w_2 is traversed during the search. Thus w1→w2w_1 \rightarrow w_2 will not enter into the calculation of LOWLINK (vv). (This can only happen if w1→w2w_1 \rightarrow w_2 is a cross-link.) On the other hand, if uu is in the same strongly connected component as w2w_2, there is no component root r→=ur \rightarrow = u on the branch u→∗w2u \rightarrow^* w_2, and v→w2v \rightarrow w_2 will be used to calculate LOWLINK (w2w_2), and also LOWLINK (vv), as desired. Thus LOWLINK (vv) is calculated correctly, and by induction LOWLINK is calculated correctly for all vertices.

Since the algorithm correctly calculates LOWLINK, it correctly identifies the roots of the strongly connected components. If such a root uu is found, the corresponding component contains all the descendants of uu which are on the stack of points when uu is discovered. These vertices are all on top of the stack of points, and are all put into a component by STRONGCONNECT. Thus STRONGCONNECT works correctly.

  1. Further applications. We have seen how the depth-first search method may be used in the construction of very efficient graph algorithms. The two algorithms presented here are in fact optimal to within a constant factor, since every edge and vertex of a graph must be examined to determine a solution to one of the problems. (Given a suitable theoretical framework, this statement may be proved rigorously.) The similarity between biconnectivity and strong connectivity revealed by the depth-first search approach is striking. The possible uses of depth-first search are very general, and are certainly not limited to the examples presented. Hopcroft and Tarjan have constructed an algorithm for finding triconnected components in O(V,E)O(V, E) time by extending the biconnectivity algorithm [8]. An algorithm for testing the planarity of a graph in O(V)O(V) time [15] is also based on depth-first search. Combining the connectivity algorithms, the planarity algorithm, and an algorithm for testing isomorphism of triconnected planar graphs [7], we may construct an algorithm to test isomorphism of arbitrary planar graphs in O(Vlog⁡V)O(V \log V) time [8]. Depth-first search is a powerful technique with many applications.

References

  1. B. L. FOX AND D. M. LANDY, An algorithm for identifying the ergodic subchains and transient states of a stochastic matrix, Comm. ACM, 11 (1968), pp. 619–621.
  2. S. W. GOLOMB AND L. D. BAUMERT, Backtrack programming, J. ACM, 12 (1965), pp. 516–524.
  3. F. HARARY, Graph Theory, Addison-Wesley, Reading, Mass., 1969.
  4. J. HOPCROFT AND R. TARJAN, Efficient algorithms for graph manipulation, Tech. Rep. 207, Computer Science Department, Stanford University, Stanford, Calif., 1971.
  5. ———, A V^2 algorithm for determining isomorphism of planar graphs, Information Processing Letters, 1 (1971), pp. 32–34.
  6. ———, Planarity testing in V log V steps: Extended abstract, Tech. Rep. 201, Computer Science Department, Stanford University, Stanford, Calif., 1971.
  7. J. HOPCROFT, An N log N algorithm for isomorphism of planar triply connected graphs, Tech. Rep. 192, Computer Science Department, Stanford University, Stanford, Calif., 1971.
  8. J. HOPCROFT AND R. TARJAN, Isomorphism of planar graphs, IBM Symposium on Complexity of Computer Computations, Yorktown Heights, N.Y., March, 1972, to be published by Plenum Press.
  9. J. HOPCROFT AND J. ULLMAN, A linear list-merging algorithm, Tech. Rep. 71-111, Cornell University Computer Science Department, Ithaca, N.Y., 1971.
  10. I. MUNRO, Efficient determination of the strongly connected components and transitive closure of a directed graph, Department of Computer Science, University of Toronto, 1971.
  11. N. J. NILSON, Problem Solving Methods in Artificial Intelligence, McGraw-Hill, New York, 1971.
  12. K. PATON, An algorithm for the blocks and cutnades of a graph, Comm. ACM, 14 (1971), pp. 468–475.
  13. P. W. PURDOM, A transitive closure algorithm, Tech. Rep. 33, Computer Sciences Department, University of Wisconsin, Madison, 1968.
  14. R. W. SHIREY, Implementation and analysis of efficient graph planarity testing algorithms, Doctoral thesis, Computer Sciences Department, University of Wisconsin, Madison, 1969.
  15. R. TARJAN, An efficient planarity algorithm, Tech. Rep. 244, Computer Science Department, Stanford University, Stanford, Calif., 1971.

Read off the page by a vision model reading the page images using olmOCR-2-7B-1025-FP8.