Chris@16
|
1 //
|
Chris@16
|
2 //=======================================================================
|
Chris@16
|
3 // Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
|
Chris@16
|
4 // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
|
Chris@16
|
5 //
|
Chris@16
|
6 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
7 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
8 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 //=======================================================================
|
Chris@16
|
10 //
|
Chris@16
|
11 #ifndef BOOST_DISJOINT_SETS_HPP
|
Chris@16
|
12 #define BOOST_DISJOINT_SETS_HPP
|
Chris@16
|
13
|
Chris@16
|
14 #include <vector>
|
Chris@16
|
15 #include <boost/graph/properties.hpp>
|
Chris@16
|
16 #include <boost/pending/detail/disjoint_sets.hpp>
|
Chris@16
|
17
|
Chris@16
|
18 namespace boost {
|
Chris@16
|
19
|
Chris@16
|
20 struct find_with_path_halving {
|
Chris@16
|
21 template <class ParentPA, class Vertex>
|
Chris@16
|
22 Vertex operator()(ParentPA p, Vertex v) {
|
Chris@16
|
23 return detail::find_representative_with_path_halving(p, v);
|
Chris@16
|
24 }
|
Chris@16
|
25 };
|
Chris@16
|
26
|
Chris@16
|
27 struct find_with_full_path_compression {
|
Chris@16
|
28 template <class ParentPA, class Vertex>
|
Chris@16
|
29 Vertex operator()(ParentPA p, Vertex v){
|
Chris@16
|
30 return detail::find_representative_with_full_compression(p, v);
|
Chris@16
|
31 }
|
Chris@16
|
32 };
|
Chris@16
|
33
|
Chris@16
|
34 // This is a generalized functor to provide disjoint sets operations
|
Chris@16
|
35 // with "union by rank" and "path compression". A disjoint-set data
|
Chris@16
|
36 // structure maintains a collection S={S1, S2, ..., Sk} of disjoint
|
Chris@16
|
37 // sets. Each set is identified by a representative, which is some
|
Chris@16
|
38 // member of of the set. Sets are represented by rooted trees. Two
|
Chris@16
|
39 // heuristics: "union by rank" and "path compression" are used to
|
Chris@16
|
40 // speed up the operations.
|
Chris@16
|
41
|
Chris@16
|
42 // Disjoint Set requires two vertex properties for internal use. A
|
Chris@16
|
43 // RankPA and a ParentPA. The RankPA must map Vertex to some Integral type
|
Chris@16
|
44 // (preferably the size_type associated with Vertex). The ParentPA
|
Chris@16
|
45 // must map Vertex to Vertex.
|
Chris@16
|
46 template <class RankPA, class ParentPA,
|
Chris@16
|
47 class FindCompress = find_with_full_path_compression
|
Chris@16
|
48 >
|
Chris@16
|
49 class disjoint_sets {
|
Chris@16
|
50 typedef disjoint_sets self;
|
Chris@16
|
51
|
Chris@16
|
52 inline disjoint_sets() {}
|
Chris@16
|
53 public:
|
Chris@16
|
54 inline disjoint_sets(RankPA r, ParentPA p)
|
Chris@16
|
55 : rank(r), parent(p) {}
|
Chris@16
|
56
|
Chris@16
|
57 inline disjoint_sets(const self& c)
|
Chris@16
|
58 : rank(c.rank), parent(c.parent) {}
|
Chris@16
|
59
|
Chris@16
|
60 // Make Set -- Create a singleton set containing vertex x
|
Chris@16
|
61 template <class Element>
|
Chris@16
|
62 inline void make_set(Element x)
|
Chris@16
|
63 {
|
Chris@16
|
64 put(parent, x, x);
|
Chris@16
|
65 typedef typename property_traits<RankPA>::value_type R;
|
Chris@16
|
66 put(rank, x, R());
|
Chris@16
|
67 }
|
Chris@16
|
68
|
Chris@16
|
69 // Link - union the two sets represented by vertex x and y
|
Chris@16
|
70 template <class Element>
|
Chris@16
|
71 inline void link(Element x, Element y)
|
Chris@16
|
72 {
|
Chris@16
|
73 detail::link_sets(parent, rank, x, y, rep);
|
Chris@16
|
74 }
|
Chris@16
|
75
|
Chris@16
|
76 // Union-Set - union the two sets containing vertex x and y
|
Chris@16
|
77 template <class Element>
|
Chris@16
|
78 inline void union_set(Element x, Element y)
|
Chris@16
|
79 {
|
Chris@16
|
80 link(find_set(x), find_set(y));
|
Chris@16
|
81 }
|
Chris@16
|
82
|
Chris@16
|
83 // Find-Set - returns the Element representative of the set
|
Chris@16
|
84 // containing Element x and applies path compression.
|
Chris@16
|
85 template <class Element>
|
Chris@16
|
86 inline Element find_set(Element x)
|
Chris@16
|
87 {
|
Chris@16
|
88 return rep(parent, x);
|
Chris@16
|
89 }
|
Chris@16
|
90
|
Chris@16
|
91 template <class ElementIterator>
|
Chris@16
|
92 inline std::size_t count_sets(ElementIterator first, ElementIterator last)
|
Chris@16
|
93 {
|
Chris@16
|
94 std::size_t count = 0;
|
Chris@16
|
95 for ( ; first != last; ++first)
|
Chris@16
|
96 if (get(parent, *first) == *first)
|
Chris@16
|
97 ++count;
|
Chris@16
|
98 return count;
|
Chris@16
|
99 }
|
Chris@16
|
100
|
Chris@16
|
101 template <class ElementIterator>
|
Chris@16
|
102 inline void normalize_sets(ElementIterator first, ElementIterator last)
|
Chris@16
|
103 {
|
Chris@16
|
104 for (; first != last; ++first)
|
Chris@16
|
105 detail::normalize_node(parent, *first);
|
Chris@16
|
106 }
|
Chris@16
|
107
|
Chris@16
|
108 template <class ElementIterator>
|
Chris@16
|
109 inline void compress_sets(ElementIterator first, ElementIterator last)
|
Chris@16
|
110 {
|
Chris@16
|
111 for (; first != last; ++first)
|
Chris@16
|
112 detail::find_representative_with_full_compression(parent, *first);
|
Chris@16
|
113 }
|
Chris@16
|
114 protected:
|
Chris@16
|
115 RankPA rank;
|
Chris@16
|
116 ParentPA parent;
|
Chris@16
|
117 FindCompress rep;
|
Chris@16
|
118 };
|
Chris@16
|
119
|
Chris@16
|
120
|
Chris@16
|
121
|
Chris@16
|
122
|
Chris@16
|
123 template <class ID = identity_property_map,
|
Chris@16
|
124 class InverseID = identity_property_map,
|
Chris@16
|
125 class FindCompress = find_with_full_path_compression
|
Chris@16
|
126 >
|
Chris@16
|
127 class disjoint_sets_with_storage
|
Chris@16
|
128 {
|
Chris@16
|
129 typedef typename property_traits<ID>::value_type Index;
|
Chris@16
|
130 typedef std::vector<Index> ParentContainer;
|
Chris@16
|
131 typedef std::vector<unsigned char> RankContainer;
|
Chris@16
|
132 public:
|
Chris@16
|
133 typedef typename ParentContainer::size_type size_type;
|
Chris@16
|
134
|
Chris@16
|
135 disjoint_sets_with_storage(size_type n = 0,
|
Chris@16
|
136 ID id_ = ID(),
|
Chris@16
|
137 InverseID inv = InverseID())
|
Chris@16
|
138 : id(id_), id_to_vertex(inv), rank(n, 0), parent(n)
|
Chris@16
|
139 {
|
Chris@16
|
140 for (Index i = 0; i < n; ++i)
|
Chris@16
|
141 parent[i] = i;
|
Chris@16
|
142 }
|
Chris@16
|
143 // note this is not normally needed
|
Chris@16
|
144 template <class Element>
|
Chris@16
|
145 inline void
|
Chris@16
|
146 make_set(Element x) {
|
Chris@16
|
147 parent[x] = x;
|
Chris@16
|
148 rank[x] = 0;
|
Chris@16
|
149 }
|
Chris@16
|
150 template <class Element>
|
Chris@16
|
151 inline void
|
Chris@16
|
152 link(Element x, Element y)
|
Chris@16
|
153 {
|
Chris@16
|
154 extend_sets(x,y);
|
Chris@16
|
155 detail::link_sets(&parent[0], &rank[0],
|
Chris@16
|
156 get(id,x), get(id,y), rep);
|
Chris@16
|
157 }
|
Chris@16
|
158 template <class Element>
|
Chris@16
|
159 inline void
|
Chris@16
|
160 union_set(Element x, Element y) {
|
Chris@16
|
161 Element rx = find_set(x);
|
Chris@16
|
162 Element ry = find_set(y);
|
Chris@16
|
163 link(rx, ry);
|
Chris@16
|
164 }
|
Chris@16
|
165 template <class Element>
|
Chris@16
|
166 inline Element find_set(Element x) {
|
Chris@16
|
167 return id_to_vertex[rep(&parent[0], get(id,x))];
|
Chris@16
|
168 }
|
Chris@16
|
169
|
Chris@16
|
170 template <class ElementIterator>
|
Chris@16
|
171 inline std::size_t count_sets(ElementIterator first, ElementIterator last)
|
Chris@16
|
172 {
|
Chris@16
|
173 std::size_t count = 0;
|
Chris@16
|
174 for ( ; first != last; ++first)
|
Chris@16
|
175 if (parent[*first] == *first)
|
Chris@16
|
176 ++count;
|
Chris@16
|
177 return count;
|
Chris@16
|
178 }
|
Chris@16
|
179
|
Chris@16
|
180 template <class ElementIterator>
|
Chris@16
|
181 inline void normalize_sets(ElementIterator first, ElementIterator last)
|
Chris@16
|
182 {
|
Chris@16
|
183 for (; first != last; ++first)
|
Chris@16
|
184 detail::normalize_node(&parent[0], *first);
|
Chris@16
|
185 }
|
Chris@16
|
186
|
Chris@16
|
187 template <class ElementIterator>
|
Chris@16
|
188 inline void compress_sets(ElementIterator first, ElementIterator last)
|
Chris@16
|
189 {
|
Chris@16
|
190 for (; first != last; ++first)
|
Chris@16
|
191 detail::find_representative_with_full_compression(&parent[0],
|
Chris@16
|
192 *first);
|
Chris@16
|
193 }
|
Chris@16
|
194
|
Chris@16
|
195 const ParentContainer& parents() { return parent; }
|
Chris@16
|
196
|
Chris@16
|
197 protected:
|
Chris@16
|
198
|
Chris@16
|
199 template <class Element>
|
Chris@16
|
200 inline void
|
Chris@16
|
201 extend_sets(Element x, Element y)
|
Chris@16
|
202 {
|
Chris@16
|
203 Index needed = get(id,x) > get(id,y) ? get(id,x) + 1 : get(id,y) + 1;
|
Chris@16
|
204 if (needed > parent.size()) {
|
Chris@16
|
205 rank.insert(rank.end(), needed - rank.size(), 0);
|
Chris@16
|
206 for (Index k = parent.size(); k < needed; ++k)
|
Chris@16
|
207 parent.push_back(k);
|
Chris@16
|
208 }
|
Chris@16
|
209 }
|
Chris@16
|
210
|
Chris@16
|
211 ID id;
|
Chris@16
|
212 InverseID id_to_vertex;
|
Chris@16
|
213 RankContainer rank;
|
Chris@16
|
214 ParentContainer parent;
|
Chris@16
|
215 FindCompress rep;
|
Chris@16
|
216 };
|
Chris@16
|
217
|
Chris@16
|
218 } // namespace boost
|
Chris@16
|
219
|
Chris@16
|
220 #endif // BOOST_DISJOINT_SETS_HPP
|