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.
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).
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;
}
| 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).
boost/graph/connected_components.hpp
| 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.
boost/graph/connected_components.hpp
| 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.
boost/graph/connected_components.hpp
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.
boost/graph/connected_components.hpp
| 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) |