Linear time depth-first search The classic
sequential algorithm for computing biconnected components in a connected
undirected graph is due to
John Hopcroft and
Robert Tarjan (1973). It runs in
linear time, and is based on
depth-first search. This algorithm is also outlined as Problem 22-2 of
Introduction to Algorithms (both 2nd and 3rd editions). The idea is to run a depth-first search while maintaining the following information: • the depth of each vertex in the depth-first-search tree (once it gets visited), and • for each vertex , the lowest depth of neighbors of all descendants of (including itself) in the depth-first-search tree, called the . The depth is standard to maintain during a depth-first search. The lowpoint of can be computed after visiting all descendants of (i.e., just before gets popped off the depth-first-search
stack) as the minimum of the depth of , the depth of all neighbors of (other than the parent of in the depth-first-search tree) and the lowpoint of all children of in the depth-first-search tree. The key fact is that a nonroot vertex is a cut vertex (or articulation point) separating two biconnected components
if and only if there is a child of such that . This property can be tested once the depth-first search returned from every child of (i.e., just before gets popped off the depth-first-search stack), and if
true, separates the graph into different biconnected components. This can be represented by computing one biconnected component out of every such (a component which contains will contain the subtree of , plus ), and then erasing the subtree of from the tree. The root vertex must be handled separately: it is a cut vertex if and only if it has at least two children in the DFS tree. Thus, it suffices to simply build one component out of each child subtree of the root (including the root).
Pseudocode GetArticulationPoints(i, d) visited[i] :=
true depth[i] := d low[i] := d childCount := 0 isArticulation :=
false for each ni
in adj[i]
do if not visited[ni]
then parent[ni] := i GetArticulationPoints(ni, d + 1) childCount := childCount + 1
if low[ni] ≥ depth[i]
then isArticulation :=
true low[i] := Min (low[i], low[ni])
else if ni ≠ parent[i]
then low[i] := Min (low[i], depth[ni])
if (parent[i] ≠
null and isArticulation)
or (parent[i] =
null and childCount > 1)
then Output i as articulation point Main GetArticulationPoints(r,0) // r is an arbitrary root Note that the terms child and parent denote the relations in the DFS tree, not the original graph.
Other algorithms A simple alternative to the above algorithm uses
chain decompositions, which are special ear decompositions depending on
DFS-trees. Chain decompositions can be computed in linear time by this
traversing rule. Let be a chain decomposition of . Then is 2-vertex-connected if and only if has minimum
degree 2 and is the only
cycle in . This gives immediately a linear-time 2-connectivity test and can be extended to list all cut vertices of in linear time using the following statement: A vertex in a connected graph (with minimum degree 2) is a cut vertex if and only if is incident to a
bridge or is the first vertex of a cycle in . The list of cut vertices can be used to create the
block-cut tree of in linear time. In the
online version of the problem, vertices and edges are added (but not removed) dynamically, and a data structure must maintain the biconnected components.
Jeffery Westbrook and
Robert Tarjan (1992) developed an efficient data structure for this problem based on
disjoint-set data structures. Specifically, it processes vertex additions and edge additions in total time, where is the
inverse Ackermann function. This time bound is proved to be optimal.
Uzi Vishkin and
Robert Tarjan (1985) designed a
parallel algorithm on CRCW
PRAM that runs in time with processors. Another algorithm has been provided by Harold Gabow, in his paper "Path-based depth-first search for strong and biconnected components" (2000). ==Related structures==