C++ Boost

Dynamic Connected Components

This section describes a family of functions and classes that calculate the connected components of an undirected graph. The algorithm used here is based on the disjoint-sets data structure [8,27] which is the best method for situations where the graph is growing (edges are being added) and the connected components information needs to be updated repeatedly. The disjoint-sets class is described in Section [*].

The following five operations are the primary functions that you will use to calculate and maintain the connected components. The objects used here are a graph g, a disjoint-sets structure ds, and vertices u and v.

Complexity

The time complexity for the whole process is O(V + E alpha(E,V)) where E is the total number of edges in the graph (by the end of the process) and V is the number of vertices. alpha is the inverse of Ackermann's function which has explosive recursively exponential growth. Therefore its inverse function grows very slowly. For all practical purposes alpha(m,n) <= 4 which means the time complexity is only slightly larger than O(V + E).

Example

Maintain the connected components of a graph while adding edges using the disjoint-sets data structure. The full source code for this example can be found in examples/dynamic_components.cpp.

  // Create a graph
  typedef adjacency_list <vecS, vecS, undirectedS> Graph;
  typedef Graph::vertex_descriptor Vertex;
  const int N = 6;
  Graph G(N);
  add_edge(G, 0, 1);
  add_edge(G, 1, 4);

  // create the disjoint-sets structure, which requires
  // rank and parent vertex properties
  std::vector<Vertex> rank(num_vertices(G));
  std::vector<Vertex> parent(num_vertices(G));
  typedef std::vector<Graph::size_type>::iterator Rank;
  typedef std::vector<Vertex>::iterator Parent;
  disjoint_sets<Rank, Parent> ds(rank.begin(), parent.begin());

  // determine the connected components
  // the results are embedded in the disjoint-sets structure
  initialize_dynamic_components(G, ds);
  dynamic_connected_components(G, ds);

  Graph::edge_descriptor e;
  bool flag;

  // Add a couple more edges and update the disjoint-sets
  tie(e,flag) = add_edge(G, 4, 0);
  ds.union_set(4,0);

  tie(e,flag) = add_edge(G, 2, 5);
  ds.union_set(2,5);
    
  cout << "An undirected graph:" << endl;
  print_graph(G, get_vertex_property(G,id_tag()));
  cout << endl;
    
  Graph::vertex_iterator i,end;
  for (tie(i,end) = vertices(G); i != end; ++i)
    cout << "representative[" << *i << "] = " << 
      ds.find_set(*i) << endl;;
  cout << endl;

  typedef component_index<int> Components;
  Components components(parent.begin(), parent.end());

  for (Components::size_type i = 0; i < components.size(); ++i) {
    cout << "component " << i << " contains: ";
    Components::value_type::iterator
      j = components[i].begin(),
      jend = components[i].end();
    for ( ; j != jend; ++j)
      cout << *j << " ";
    cout << endl;
  }


initialize_dynamic_components

Graphs: undirected
Properties: rank, parent (in disjoint-sets)
Complexity:

template <class VertexListGraph, class DisjointSets> 
void initialize_dynamic_components(VertexListGraph& G, DisjointSets& ds)

This prepares the disjoint-sets data structure for the dynamic connected components algorithm by making each vertex in the graph a member of its own component (or set).

Where Defined

boost/graph/connected_components.hpp


dynamic_connected_components

Graphs: undirected
Properties: rank, parent (in disjoint-sets)
Complexity: O(E)

template <class EdgeListGraph, class DisjointSets>
void dynamic_connected_components(EdgeListGraph& g, DisjointSets& ds)

This function calculates the connected components of the graph, embedding the results in the disjoint-sets data structure.

Where Defined

boost/graph/connected_components.hpp

Requirements on Types


same_component

Properties: rank, parent (in disjoint-sets)
Complexity: O(alpha(E,V))

template <class Vertex, class DisjointSet>
bool same_component(Vertex u, Vertex v, DisjointSet& ds)

This function determines whether u and v are in the same component.

Where Defined

boost/graph/connected_components.hpp

Requirements on Types


component_index

component_index<Index>

The is a class that provides an STL container-like view for the components of the graph. Each component is a container-like object, and the component_index object provides access to the component objects via operator[]. A component_index object is initialized with the parents property in the disjoint-sets calculated from the dynamic_connected_components() function.

Where Defined

boost/graph/connected_components.hpp

Members

Member Description
size_type The type used for representing the number of components.
value_type The type for a component object. The component type has the following members.
value_type::value_type The value type of a component object is a vertex ID.
value_type::iterator This iterator can be used to traverse all of the vertices in the component. This iterator dereferences to give a vertex ID.
value_type::const_iterator The const iterator.
value_type::iterator value_type::begin() const Return an iterator pointing to the first vertex in the component.
value_type::iterator value_type::end() const Return an iterator pointing past the end of the last vertex in the component.
template <class ComponentsContainer> component_index(const ComponentsContainer& c) Construct the component_index using the information from the components container c which was the result of executing connected_components_on_edgelist.
value_type operator[](size_type i) Returns the ith component in the graph.
size_type component_index::size() Returns the number of components in the graph.


Copyright © 2000 Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu)
Lie-Quan Lee, Univ.of Notre Dame (llee1@lsc.nd.edu)
Andrew Lumsdaine, Univ.of Notre Dame (lums@lsc.nd.edu)