diff --git a/doc/challenge.html b/doc/challenge.html
index 072ba134e..89a34dec6 100644
--- a/doc/challenge.html
+++ b/doc/challenge.html
@@ -37,7 +37,7 @@
Boost Graph Library Challenge and To-Do Items
mutable_queue.hpp, fibonacci_heap.hpp.
Somehow merge implementation with Dietmer's heaps and queues.
- disjoint_sets
+ disjoint_sets (see )
Construct a set of planar graph algorithms.
diff --git a/doc/disjoint_sets.html b/doc/disjoint_sets.html
new file mode 100644
index 000000000..4bff1bf98
--- /dev/null
+++ b/doc/disjoint_sets.html
@@ -0,0 +1,309 @@
+
+
+
+
+
+
+
+ Boost Disjoint Sets
+
+
+
+ 
+
+ Disjoint
+ Sets
+
+disjoint_sets<Rank, Parent, FindCompress>
+
+
+ This is a class that provides disjoint set operations with union by
+ rank and path compression. A disjoint-sets data structure
+ maintains a collection S = {S1, S2, ...,
+ Sk} of disjoint sets. Each set is identified by a
+ representative which is some member of of the set. Sets are
+ represented by rooted trees which are encoded in the Parent
+ property map. Two heuristics: "union by rank" and "path compression" are
+ used to speed up the operations [1, 2].
+
+ Where Defined
boost/pending/disjoint_sets.hpp
+
+ Template Parameters
+
+
+
+ | Rank |
+
+ must be a model of ReadWritePropertyMap
+ with an integer value type and a key type equal to the set's element
+ type. |
+
+
+
+ | Parent |
+
+ must be a model of ReadWritePropertyMap
+ and the key and value type the same as the set's element type. |
+
+
+
+ | FindCompress |
+
+ should be one of the find representative and path compress function
+ objects. |
+
+
+
+ Example
+
+ A typical usage pattern for disjoint_sets can be seen in the
+ kruskal_minimum_spanning_tree()
+ algorithm. In this example, we call link() instead of
+ union_set() because u and v were obtained from
+ find_set() and therefore are already the representatives for their
+ sets.
+
+ ...
+ disjoint_sets<Rank, Parent, FindCompress> dsets(rank, p);
+
+ for (ui = vertices(G).first; ui != vertices(G).second; ++ui)
+ dsets.make_set(*ui);
+ ...
+ while ( !Q.empty() ) {
+ e = Q.front();
+ Q.pop();
+ u = dsets.find_set(source(e));
+ v = dsets.find_set(target(e));
+ if ( u != v ) {
+ *out++ = e;
+ dsets.link(u, v);
+ }
+ }
+
+
+ Members
+
+
+
+ | Member |
+
+ Description |
+
+
+
+ | disjoint_sets(Rank r, Parent p) |
+
+ Constructor. |
+
+
+
+ | disjoint_sets(const disjoint_sets& x) |
+
+ Copy constructor. |
+
+
+
+ template <class Element>
+ void make_set(Element x) |
+
+ Creates a singleton set containing Element x. |
+
+
+
+ template <class Element>
+ void link(Element x, Element y) |
+
+ Union the two sets represented by element x and
+ y. |
+
+
+
+ template <class Element>
+ void union_set(Element x, Element y) |
+
+ Union the two sets that contain elements x and
+ y. This is equivalent to
+ link(find_set(x),find_set(y)). |
+
+
+
+ template <class Element>
+ Element find_set(Element x) |
+
+ Return the representative for the set containing element
+ x. |
+
+
+
+ template <class ElementIterator>
+ std::size_t count_sets(ElementIterator first, ElementIterator
+ last) |
+
+ Returns the number of disjoint sets. |
+
+
+
+ template <class ElementIterator>
+ void compress_sets(ElementIterator first, ElementIterator
+ last) |
+
+ Flatten the parents tree so that the parent of every element is its
+ representative. |
+
+
+
+ Complexity
+
+ The time complexity is O(m alpha(m,n)), where alpha is the
+ inverse Ackermann's function, m is the number of disjoint-set
+ operations (make_set(), find_set(), and link()
+ and n is the number of elements. The alpha function grows
+ very slowly, much more slowly than the log function.
+
+ See Also
incremental_connected_components()
+
+
+disjoint_sets_with_storage<ID,InverseID,FindCompress>
+
+
+ This class manages the storage for the rank and parent properties
+ internally. The storage is in arrays, which are indexed by element ID,
+ hence the requirement for the ID and InverseID functors.
+ The rank and parent properties are initialized during construction so the
+ each element is in a set by itself (so it is not necessary to initialize
+ objects of this class with the
+ initialize_incremental_components() function). This class is
+ especially useful when computing the (dynamic) connected components of an
+ edge_list graph which does not provide a place to store vertex
+ properties.
+
+ Template Parameters
+
+
+
+ | Parameter |
+
+ Description |
+
+ Default |
+
+
+
+ | ID |
+
+ must be a model of ReadablePropertyMap that
+ maps elements to integers between zero 0 and N, the total number of
+ elements in the sets. |
+
+ boost::identity_property_map |
+
+
+
+ | InverseID |
+
+ must be a model of ReadablePropertyMap that
+ maps integers to elements. |
+
+ boost::identity_property_map |
+
+
+
+ | FindCompress |
+
+ should be one of the find representative and path compress function
+ objects. |
+
+ representative_with_full_path_compression |
+
+
+
+ Members
+
+ This class has all of the members in disjoint_sets as well as
+ the following members.
+
+disjoint_sets_with_storage(size_type n = 0,
+ ID id = ID(),
+ InverseID inv = InverseID())
+
Constructor.
+
+template <class ElementIterator>
+void disjoint_sets_with_storage::
+ normalize_sets(ElementIterator first, ElementIterator last)
+
This rearranges the representatives such that the representative of
+each set is the element with the smallest ID.
+ Postcondition: v >= parent[v]
+ Precondition: the disjoint sets structure must be compressed.
+
+
+
+
+representative_with_path_halving<Parent>
+
+
+ This is a functor which finds the representative vertex for the same
+ component as the element x. While traversing up the representative
+ tree, the functor also applies the path halving technique to shorten the
+ height of the tree.
+
+Element operator()(Parent p, Element x)
+
+
+
+
+
+representative_with_full_path_compression<Parent>
+
+
+ This is a functor which finds the representative element for the set
+ that element x belongs to.
+
+Element operator()(Parent p, Element x)
+
+
+
+
+
+ 
+
+ Revised
+ 01
+ December, 2006
+
+
+
+ Distributed under the Boost Software License, Version 1.0. (See
+ accompanying file LICENSE_1_0.txt or
+ copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
diff --git a/doc/disjoint_sets_biblio.html b/doc/disjoint_sets_biblio.html
new file mode 100644
index 000000000..54fc44a0d
--- /dev/null
+++ b/doc/disjoint_sets_biblio.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+ Boost Utility Library: Bibliography
+
+
+
+ 
+
+ Bibliography
+
+
+ - 1
+
+ - R. E. Tarjan.
+ Data Structures and Network Algorithms.
+ Society for Industrial and Applied Mathematics, 1983.
+
+ -
+
+ - 2
+
+ - T. Cormen, C. Leiserson, and R. Rivest.
+ Introduction to Algorithms.
+ McGraw-Hill, 1990.
+
+
+
+ 
+
+ Revised
+ 01
+ December, 2006
+
+
+
+ Distributed under the Boost Software License, Version 1.0. (See
+ accompanying file LICENSE_1_0.txt or
+ copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
diff --git a/doc/index.html b/doc/index.html
index b4e8b650a..61bc71b15 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -287,7 +287,6 @@ Data Structures
The edge_list class is an adaptor that takes any kind of edge
iterator and implements an Edge List Graph.
-
diff --git a/include/boost/pending/detail/disjoint_sets.hpp b/include/boost/pending/detail/disjoint_sets.hpp
new file mode 100644
index 000000000..6d1ec3ac7
--- /dev/null
+++ b/include/boost/pending/detail/disjoint_sets.hpp
@@ -0,0 +1,88 @@
+// (C) Copyright Jeremy Siek 2004
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_DETAIL_DISJOINT_SETS_HPP
+#define BOOST_DETAIL_DISJOINT_SETS_HPP
+
+namespace boost {
+
+namespace detail {
+
+template
+Vertex
+find_representative_with_path_halving(ParentPA p, Vertex v)
+{
+ Vertex parent = get(p, v);
+ Vertex grandparent = get(p, parent);
+ while (parent != grandparent) {
+ put(p, v, grandparent);
+ v = grandparent;
+ parent = get(p, v);
+ grandparent = get(p, parent);
+ }
+ return parent;
+}
+
+template
+Vertex
+find_representative_with_full_compression(ParentPA parent, Vertex v)
+{
+ Vertex old = v;
+ Vertex ancestor = get(parent, v);
+ while (ancestor != v) {
+ v = ancestor;
+ ancestor = get(parent, v);
+ }
+ v = get(parent, old);
+ while (ancestor != v) {
+ put(parent, old, ancestor);
+ old = v;
+ v = get(parent, old);
+ }
+ return ancestor;
+}
+
+/* the postcondition of link sets is:
+ component_representative(i) == component_representative(j)
+ */
+template
+inline void
+link_sets(ParentPA p, RankPA rank, Vertex i, Vertex j,
+ ComponentRepresentative comp_rep)
+{
+ i = comp_rep(p, i);
+ j = comp_rep(p, j);
+ if (i == j) return;
+ if (get(rank, i) > get(rank, j))
+ put(p, j, i);
+ else {
+ put(p, i, j);
+ if (get(rank, i) == get(rank, j))
+ put(rank, j, get(rank, j) + 1);
+ }
+}
+
+// normalize components has the following postcondidition:
+// i >= p[i]
+// that is, the representative is the node with the smallest index in its class
+// as its precondition it it assumes that the node container is compressed
+
+template
+inline void
+normalize_node(ParentPA p, Vertex i)
+{
+ if (i > get(p,i) || get(p, get(p,i)) != get(p,i))
+ put(p,i, get(p, get(p,i)));
+ else {
+ put(p, get(p,i), i);
+ put(p, i, i);
+ }
+}
+
+ } // namespace detail
+} // namespace boost
+
+#endif // BOOST_DETAIL_DISJOINT_SETS_HPP
diff --git a/include/boost/pending/disjoint_sets.hpp b/include/boost/pending/disjoint_sets.hpp
new file mode 100644
index 000000000..e64bc2b71
--- /dev/null
+++ b/include/boost/pending/disjoint_sets.hpp
@@ -0,0 +1,220 @@
+//
+//=======================================================================
+// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
+// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//=======================================================================
+//
+#ifndef BOOST_DISJOINT_SETS_HPP
+#define BOOST_DISJOINT_SETS_HPP
+
+#include
+#include
+#include
+
+namespace boost {
+
+ struct find_with_path_halving {
+ template
+ Vertex operator()(ParentPA p, Vertex v) {
+ return detail::find_representative_with_path_halving(p, v);
+ }
+ };
+
+ struct find_with_full_path_compression {
+ template
+ Vertex operator()(ParentPA p, Vertex v){
+ return detail::find_representative_with_full_compression(p, v);
+ }
+ };
+
+ // This is a generalized functor to provide disjoint sets operations
+ // with "union by rank" and "path compression". A disjoint-set data
+ // structure maintains a collection S={S1, S2, ..., Sk} of disjoint
+ // sets. Each set is identified by a representative, which is some
+ // member of of the set. Sets are represented by rooted trees. Two
+ // heuristics: "union by rank" and "path compression" are used to
+ // speed up the operations.
+
+ // Disjoint Set requires two vertex properties for internal use. A
+ // RankPA and a ParentPA. The RankPA must map Vertex to some Integral type
+ // (preferably the size_type associated with Vertex). The ParentPA
+ // must map Vertex to Vertex.
+ template
+ class disjoint_sets {
+ typedef disjoint_sets self;
+
+ inline disjoint_sets() {}
+ public:
+ inline disjoint_sets(RankPA r, ParentPA p)
+ : rank(r), parent(p) {}
+
+ inline disjoint_sets(const self& c)
+ : rank(c.rank), parent(c.parent) {}
+
+ // Make Set -- Create a singleton set containing vertex x
+ template
+ inline void make_set(Element x)
+ {
+ put(parent, x, x);
+ typedef typename property_traits::value_type R;
+ put(rank, x, R());
+ }
+
+ // Link - union the two sets represented by vertex x and y
+ template
+ inline void link(Element x, Element y)
+ {
+ detail::link_sets(parent, rank, x, y, rep);
+ }
+
+ // Union-Set - union the two sets containing vertex x and y
+ template
+ inline void union_set(Element x, Element y)
+ {
+ link(find_set(x), find_set(y));
+ }
+
+ // Find-Set - returns the Element representative of the set
+ // containing Element x and applies path compression.
+ template
+ inline Element find_set(Element x)
+ {
+ return rep(parent, x);
+ }
+
+ template
+ inline std::size_t count_sets(ElementIterator first, ElementIterator last)
+ {
+ std::size_t count = 0;
+ for ( ; first != last; ++first)
+ if (get(parent, *first) == *first)
+ ++count;
+ return count;
+ }
+
+ template
+ inline void normalize_sets(ElementIterator first, ElementIterator last)
+ {
+ for (; first != last; ++first)
+ detail::normalize_node(parent, *first);
+ }
+
+ template
+ inline void compress_sets(ElementIterator first, ElementIterator last)
+ {
+ for (; first != last; ++first)
+ detail::find_representative_with_full_compression(parent, *first);
+ }
+ protected:
+ RankPA rank;
+ ParentPA parent;
+ FindCompress rep;
+ };
+
+
+
+
+ template
+ class disjoint_sets_with_storage
+ {
+ typedef typename property_traits::value_type Index;
+ typedef std::vector ParentContainer;
+ typedef std::vector RankContainer;
+ public:
+ typedef typename ParentContainer::size_type size_type;
+
+ disjoint_sets_with_storage(size_type n = 0,
+ ID id_ = ID(),
+ InverseID inv = InverseID())
+ : id(id_), id_to_vertex(inv), rank(n, 0), parent(n)
+ {
+ for (Index i = 0; i < n; ++i)
+ parent[i] = i;
+ }
+ // note this is not normally needed
+ template
+ inline void
+ make_set(Element x) {
+ parent[x] = x;
+ rank[x] = 0;
+ }
+ template
+ inline void
+ link(Element x, Element y)
+ {
+ extend_sets(x,y);
+ detail::link_sets(&parent[0], &rank[0],
+ get(id,x), get(id,y), rep);
+ }
+ template
+ inline void
+ union_set(Element x, Element y) {
+ Element rx = find_set(x);
+ Element ry = find_set(y);
+ link(rx, ry);
+ }
+ template
+ inline Element find_set(Element x) {
+ return id_to_vertex[rep(&parent[0], get(id,x))];
+ }
+
+ template
+ inline std::size_t count_sets(ElementIterator first, ElementIterator last)
+ {
+ std::size_t count = 0;
+ for ( ; first != last; ++first)
+ if (parent[*first] == *first)
+ ++count;
+ return count;
+ }
+
+ template
+ inline void normalize_sets(ElementIterator first, ElementIterator last)
+ {
+ for (; first != last; ++first)
+ detail::normalize_node(&parent[0], *first);
+ }
+
+ template
+ inline void compress_sets(ElementIterator first, ElementIterator last)
+ {
+ for (; first != last; ++first)
+ detail::find_representative_with_full_compression(&parent[0],
+ *first);
+ }
+
+ const ParentContainer& parents() { return parent; }
+
+ protected:
+
+ template
+ inline void
+ extend_sets(Element x, Element y)
+ {
+ Index needed = get(id,x) > get(id,y) ? get(id,x) + 1 : get(id,y) + 1;
+ if (needed > parent.size()) {
+ rank.insert(rank.end(), needed - rank.size(), 0);
+ for (Index k = parent.size(); k < needed; ++k)
+ parent.push_back(k);
+ }
+ }
+
+ ID id;
+ InverseID id_to_vertex;
+ RankContainer rank;
+ ParentContainer parent;
+ FindCompress rep;
+ };
+
+} // namespace boost
+
+#endif // BOOST_DISJOINT_SETS_HPP
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index e0c07cf25..25f058bf9 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -48,6 +48,7 @@ alias graph_test_regular :
[ compile dijkstra_cc.cpp ]
[ run dijkstra_heap_performance.cpp : 10000 ]
[ run dijkstra_no_color_map_compare.cpp : 10000 ]
+ [ run disjoint_set_test.cpp ]
[ run dominator_tree_test.cpp ]
# Unused and deprecated.
diff --git a/test/disjoint_set_test.cpp b/test/disjoint_set_test.cpp
new file mode 100644
index 000000000..cd588396d
--- /dev/null
+++ b/test/disjoint_set_test.cpp
@@ -0,0 +1,76 @@
+// (C) Copyright Jeremy Siek 2002.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include
+#include
+#include
+
+template
+struct test_disjoint_set {
+ static void do_test()
+ {
+ // The following tests are pretty lame, just a basic sanity check.
+ // Industrial strength tests still need to be written.
+
+#if !defined(__MWERKS__) || __MWERKS__ > 0x3003
+ std::size_t elts[]
+#else
+ std::size_t elts[4]
+#endif
+ = { 0, 1, 2, 3 };
+
+ const int N = sizeof(elts)/sizeof(*elts);
+
+ DisjointSet ds(N);
+
+ ds.make_set(elts[0]);
+ ds.make_set(elts[1]);
+ ds.make_set(elts[2]);
+ ds.make_set(elts[3]);
+
+ BOOST_CHECK(ds.find_set(0) != ds.find_set(1));
+ BOOST_CHECK(ds.find_set(0) != ds.find_set(2));
+ BOOST_CHECK(ds.find_set(0) != ds.find_set(3));
+ BOOST_CHECK(ds.find_set(1) != ds.find_set(2));
+ BOOST_CHECK(ds.find_set(1) != ds.find_set(3));
+ BOOST_CHECK(ds.find_set(2) != ds.find_set(3));
+
+
+ ds.union_set(0, 1);
+ ds.union_set(2, 3);
+ BOOST_CHECK(ds.find_set(0) != ds.find_set(3));
+ int a = ds.find_set(0);
+ BOOST_CHECK(a == ds.find_set(1));
+ int b = ds.find_set(2);
+ BOOST_CHECK(b == ds.find_set(3));
+
+ ds.link(a, b);
+ BOOST_CHECK(ds.find_set(a) == ds.find_set(b));
+ BOOST_CHECK(1 == ds.count_sets(elts, elts + N));
+
+ ds.normalize_sets(elts, elts + N);
+ ds.compress_sets(elts, elts + N);
+ BOOST_CHECK(1 == ds.count_sets(elts, elts + N));
+ }
+};
+
+int
+test_main(int, char*[])
+{
+ using namespace boost;
+ {
+ typedef
+ disjoint_sets_with_storage ds_type;
+ test_disjoint_set::do_test();
+ }
+ {
+ typedef
+ disjoint_sets_with_storage ds_type;
+ test_disjoint_set::do_test();
+ }
+ return boost::exit_success;
+}