beckerjc@150
|
1 |
// -*- c++ -*- //
|
beckerjc@218
|
2 |
#ifndef HUGO_UNION_FIND_H
|
beckerjc@218
|
3 |
#define HUGO_UNION_FIND_H
|
beckerjc@150
|
4 |
|
beckerjc@150
|
5 |
#include <vector>
|
beckerjc@394
|
6 |
#include <list>
|
beckerjc@150
|
7 |
#include <utility>
|
beckerjc@394
|
8 |
#include <algorithm>
|
beckerjc@394
|
9 |
|
beckerjc@394
|
10 |
#include <invalid.h>
|
beckerjc@150
|
11 |
|
beckerjc@150
|
12 |
namespace hugo {
|
beckerjc@150
|
13 |
|
beckerjc@150
|
14 |
template <typename T, typename TIntMap>
|
beckerjc@150
|
15 |
class UnionFind {
|
beckerjc@150
|
16 |
|
beckerjc@150
|
17 |
public:
|
beckerjc@150
|
18 |
typedef T ElementType;
|
beckerjc@150
|
19 |
typedef std::pair<int,int> PairType;
|
beckerjc@150
|
20 |
|
beckerjc@150
|
21 |
private:
|
beckerjc@150
|
22 |
std::vector<PairType> data;
|
beckerjc@150
|
23 |
TIntMap& map;
|
beckerjc@150
|
24 |
|
beckerjc@150
|
25 |
public:
|
beckerjc@150
|
26 |
UnionFind(TIntMap& m) : map(m) {}
|
beckerjc@150
|
27 |
|
beckerjc@150
|
28 |
|
beckerjc@394
|
29 |
int find(T a)
|
beckerjc@150
|
30 |
{
|
beckerjc@349
|
31 |
int comp0 = map[a];
|
beckerjc@150
|
32 |
if (comp0 < 0) {
|
beckerjc@394
|
33 |
return insert(a);
|
beckerjc@150
|
34 |
}
|
beckerjc@150
|
35 |
int comp = comp0;
|
beckerjc@150
|
36 |
int next;
|
beckerjc@150
|
37 |
while ( (next = data[comp].first) != comp) {
|
beckerjc@150
|
38 |
comp = next;
|
beckerjc@150
|
39 |
}
|
beckerjc@150
|
40 |
while ( (next = data[comp0].first) != comp) {
|
beckerjc@150
|
41 |
data[comp0].first = comp;
|
beckerjc@150
|
42 |
comp0 = next;
|
beckerjc@150
|
43 |
}
|
beckerjc@150
|
44 |
|
beckerjc@150
|
45 |
return comp;
|
beckerjc@150
|
46 |
}
|
beckerjc@150
|
47 |
|
beckerjc@394
|
48 |
int insert(T a)
|
beckerjc@150
|
49 |
{
|
beckerjc@150
|
50 |
int n = data.size();
|
beckerjc@394
|
51 |
data.push_back(std::make_pair(n, 1));
|
beckerjc@150
|
52 |
map.set(a,n);
|
beckerjc@150
|
53 |
return n;
|
beckerjc@150
|
54 |
}
|
beckerjc@150
|
55 |
|
beckerjc@394
|
56 |
bool join(T a, T b)
|
beckerjc@150
|
57 |
{
|
beckerjc@394
|
58 |
int ca = find(a);
|
beckerjc@394
|
59 |
int cb = find(b);
|
beckerjc@150
|
60 |
|
beckerjc@150
|
61 |
if ( ca == cb )
|
beckerjc@150
|
62 |
return false;
|
beckerjc@150
|
63 |
|
beckerjc@150
|
64 |
if ( data[ca].second > data[cb].second ) {
|
beckerjc@150
|
65 |
data[cb].first = ca;
|
beckerjc@150
|
66 |
data[ca].second += data[cb].second;
|
beckerjc@150
|
67 |
}
|
beckerjc@150
|
68 |
else {
|
beckerjc@150
|
69 |
data[ca].first = cb;
|
beckerjc@150
|
70 |
data[cb].second += data[ca].second;
|
beckerjc@150
|
71 |
}
|
beckerjc@150
|
72 |
return true;
|
beckerjc@150
|
73 |
}
|
beckerjc@150
|
74 |
|
beckerjc@394
|
75 |
int size(T a)
|
beckerjc@218
|
76 |
{
|
beckerjc@394
|
77 |
int ca = find(a);
|
beckerjc@218
|
78 |
return data[ca].second;
|
beckerjc@218
|
79 |
}
|
beckerjc@218
|
80 |
|
beckerjc@150
|
81 |
};
|
beckerjc@150
|
82 |
|
beckerjc@394
|
83 |
|
beckerjc@394
|
84 |
|
beckerjc@394
|
85 |
|
beckerjc@394
|
86 |
/*******************************************************/
|
beckerjc@394
|
87 |
|
beckerjc@394
|
88 |
|
beckerjc@394
|
89 |
|
beckerjc@394
|
90 |
template <typename T>
|
beckerjc@394
|
91 |
struct UnionFindEnumItem {
|
beckerjc@394
|
92 |
|
beckerjc@394
|
93 |
typedef std::list<UnionFindEnumItem> ItemList;
|
beckerjc@394
|
94 |
typedef std::list<ItemList> ClassList;
|
beckerjc@394
|
95 |
typedef typename ItemList::iterator IIter;
|
beckerjc@394
|
96 |
typedef typename ClassList::iterator CIter;
|
beckerjc@394
|
97 |
|
beckerjc@394
|
98 |
T me;
|
beckerjc@394
|
99 |
IIter parent;
|
beckerjc@394
|
100 |
int size;
|
beckerjc@394
|
101 |
CIter my_class;
|
beckerjc@394
|
102 |
|
beckerjc@394
|
103 |
UnionFindEnumItem() {}
|
beckerjc@394
|
104 |
UnionFindEnumItem(const T &_me, CIter _my_class):
|
beckerjc@394
|
105 |
me(_me), size(1), my_class(_my_class) {}
|
beckerjc@394
|
106 |
};
|
beckerjc@394
|
107 |
|
beckerjc@394
|
108 |
template <typename T, template <typename Item> class Map>
|
beckerjc@394
|
109 |
class UnionFindEnum {
|
beckerjc@394
|
110 |
|
beckerjc@394
|
111 |
typedef std::list<UnionFindEnumItem<T> > ItemList;
|
beckerjc@394
|
112 |
typedef std::list<ItemList> ClassList;
|
beckerjc@394
|
113 |
typedef typename ItemList::iterator IIter;
|
beckerjc@394
|
114 |
typedef typename ItemList::const_iterator IcIter;
|
beckerjc@394
|
115 |
typedef typename ClassList::iterator CIter;
|
beckerjc@394
|
116 |
typedef typename ClassList::const_iterator CcIter;
|
beckerjc@394
|
117 |
|
beckerjc@394
|
118 |
public:
|
beckerjc@394
|
119 |
typedef T ElementType;
|
beckerjc@394
|
120 |
typedef UnionFindEnumItem<T> ItemType;
|
beckerjc@394
|
121 |
typedef Map< IIter > MapType;
|
beckerjc@394
|
122 |
|
beckerjc@394
|
123 |
private:
|
beckerjc@394
|
124 |
MapType& m;
|
beckerjc@394
|
125 |
ClassList classes;
|
beckerjc@394
|
126 |
|
beckerjc@394
|
127 |
// IIter where(const T &a) { return m[a]; }
|
beckerjc@394
|
128 |
// IIter parent(IIter a) { return a->parent; }
|
beckerjc@394
|
129 |
// P sibling(P a) { return &m[a->sibling]; }
|
beckerjc@394
|
130 |
|
beckerjc@394
|
131 |
IIter _find(IIter a) const {
|
beckerjc@394
|
132 |
IIter comp = a;
|
beckerjc@394
|
133 |
IIter next;
|
beckerjc@394
|
134 |
while( (next = comp->parent) != comp ) {
|
beckerjc@394
|
135 |
comp = next;
|
beckerjc@394
|
136 |
}
|
beckerjc@394
|
137 |
|
beckerjc@394
|
138 |
IIter comp1 = a;
|
beckerjc@394
|
139 |
while( (next = comp1->parent) != comp ) {
|
beckerjc@394
|
140 |
comp1->parent = comp->parent;
|
beckerjc@394
|
141 |
comp1 = next;
|
beckerjc@394
|
142 |
}
|
beckerjc@394
|
143 |
return comp;
|
beckerjc@394
|
144 |
}
|
beckerjc@394
|
145 |
|
beckerjc@394
|
146 |
public:
|
beckerjc@394
|
147 |
UnionFindEnum(MapType& _m) : m(_m) {}
|
beckerjc@394
|
148 |
|
beckerjc@394
|
149 |
void insert(const T &a)
|
beckerjc@394
|
150 |
{
|
beckerjc@394
|
151 |
|
beckerjc@394
|
152 |
|
beckerjc@394
|
153 |
classes.push_back(ItemList());
|
beckerjc@394
|
154 |
CIter aclass = classes.end();
|
beckerjc@394
|
155 |
--aclass;
|
beckerjc@394
|
156 |
|
beckerjc@394
|
157 |
ItemList &alist = *aclass;
|
beckerjc@394
|
158 |
alist.push_back(ItemType(a, aclass));
|
beckerjc@394
|
159 |
IIter ai = alist.begin();
|
beckerjc@394
|
160 |
|
beckerjc@394
|
161 |
ai->parent = ai;
|
beckerjc@394
|
162 |
m.set(a, ai);
|
beckerjc@394
|
163 |
|
beckerjc@394
|
164 |
}
|
beckerjc@394
|
165 |
|
beckerjc@394
|
166 |
T find(const T &a) const {
|
beckerjc@394
|
167 |
return _find(m[a])->me;
|
beckerjc@394
|
168 |
}
|
beckerjc@394
|
169 |
|
beckerjc@394
|
170 |
bool join(T a, T b) {
|
beckerjc@394
|
171 |
|
beckerjc@394
|
172 |
IIter ca = _find(m[a]);
|
beckerjc@394
|
173 |
IIter cb = _find(m[b]);
|
beckerjc@394
|
174 |
|
beckerjc@394
|
175 |
if ( ca == cb ) {
|
beckerjc@394
|
176 |
return false;
|
beckerjc@394
|
177 |
}
|
beckerjc@394
|
178 |
|
beckerjc@394
|
179 |
if ( ca->size > cb->size ) {
|
beckerjc@394
|
180 |
|
beckerjc@394
|
181 |
cb->parent = ca->parent;
|
beckerjc@394
|
182 |
ca->size += cb->size;
|
beckerjc@394
|
183 |
|
beckerjc@394
|
184 |
ItemList &alist = *ca->my_class;
|
beckerjc@394
|
185 |
alist.splice(alist.end(),*cb->my_class);
|
beckerjc@394
|
186 |
|
beckerjc@394
|
187 |
classes.erase(cb->my_class);
|
beckerjc@394
|
188 |
cb->my_class = 0;
|
beckerjc@394
|
189 |
}
|
beckerjc@394
|
190 |
else {
|
beckerjc@394
|
191 |
|
beckerjc@394
|
192 |
ca->parent = cb->parent;
|
beckerjc@394
|
193 |
cb->size += ca->size;
|
beckerjc@394
|
194 |
|
beckerjc@394
|
195 |
ItemList &blist = *cb->my_class;
|
beckerjc@394
|
196 |
blist.splice(blist.end(),*ca->my_class);
|
beckerjc@394
|
197 |
|
beckerjc@394
|
198 |
classes.erase(ca->my_class);
|
beckerjc@394
|
199 |
ca->my_class = 0;
|
beckerjc@394
|
200 |
}
|
beckerjc@394
|
201 |
|
beckerjc@394
|
202 |
return true;
|
beckerjc@394
|
203 |
}
|
beckerjc@394
|
204 |
|
beckerjc@394
|
205 |
int size(const T &a) const {
|
beckerjc@394
|
206 |
return _find(m[a])->size;
|
beckerjc@394
|
207 |
}
|
beckerjc@394
|
208 |
|
beckerjc@394
|
209 |
|
beckerjc@394
|
210 |
void split(const T &a) {
|
beckerjc@394
|
211 |
|
beckerjc@394
|
212 |
IIter ca = _find(m[a]);
|
beckerjc@394
|
213 |
|
beckerjc@394
|
214 |
if ( ca->size == 1 )
|
beckerjc@394
|
215 |
return;
|
beckerjc@394
|
216 |
|
beckerjc@394
|
217 |
CIter aclass = ca->my_class;
|
beckerjc@394
|
218 |
|
beckerjc@394
|
219 |
for(IIter curr = ca; ++curr != aclass->end(); curr=ca) {
|
beckerjc@394
|
220 |
classes.push_back(ItemList());
|
beckerjc@394
|
221 |
CIter nl = --classes.end();
|
beckerjc@394
|
222 |
nl->splice(nl->end(), *aclass, curr);
|
beckerjc@394
|
223 |
|
beckerjc@394
|
224 |
curr->size=1;
|
beckerjc@394
|
225 |
curr->parent=curr;
|
beckerjc@394
|
226 |
curr->my_class = nl;
|
beckerjc@394
|
227 |
}
|
beckerjc@394
|
228 |
|
beckerjc@394
|
229 |
ca->size=1;
|
beckerjc@394
|
230 |
return;
|
beckerjc@394
|
231 |
}
|
beckerjc@394
|
232 |
|
beckerjc@394
|
233 |
void erase(const T &a) {
|
beckerjc@394
|
234 |
|
beckerjc@394
|
235 |
IIter ma = m[a];
|
beckerjc@394
|
236 |
if (ma == 0) return;
|
beckerjc@394
|
237 |
|
beckerjc@394
|
238 |
IIter la = _find(ma);
|
beckerjc@394
|
239 |
if (la == ma) {
|
beckerjc@394
|
240 |
if (ma -> size == 1){
|
beckerjc@394
|
241 |
classes.erase(ma->my_class);
|
beckerjc@394
|
242 |
m.set(a,0);
|
beckerjc@394
|
243 |
return;
|
beckerjc@394
|
244 |
}
|
beckerjc@394
|
245 |
++la;
|
beckerjc@394
|
246 |
la->size = ma->size - 1;
|
beckerjc@394
|
247 |
la->my_class = ma->my_class;
|
beckerjc@394
|
248 |
}
|
beckerjc@394
|
249 |
|
beckerjc@394
|
250 |
for (IIter i = la; i != la->my_class->end(); ++i) {
|
beckerjc@394
|
251 |
i->parent = la;
|
beckerjc@394
|
252 |
}
|
beckerjc@394
|
253 |
|
beckerjc@394
|
254 |
la->my_class->erase(ma);
|
beckerjc@394
|
255 |
m.set(a,0);
|
beckerjc@394
|
256 |
}
|
beckerjc@394
|
257 |
|
beckerjc@394
|
258 |
void eraseClass(const T &a) {
|
beckerjc@394
|
259 |
IIter ma = m[a];
|
beckerjc@394
|
260 |
if (ma == 0) return;
|
beckerjc@394
|
261 |
# ifdef DEBUG
|
beckerjc@394
|
262 |
CIter c = _find(ma)->my_class;
|
beckerjc@394
|
263 |
for (IIter i=c->begin(); i!=c->end(); ++i)
|
beckerjc@394
|
264 |
m.set(i->me, 0);
|
beckerjc@394
|
265 |
# endif
|
beckerjc@394
|
266 |
classes.erase(_find(ma)->my_class);
|
beckerjc@394
|
267 |
}
|
beckerjc@394
|
268 |
|
beckerjc@394
|
269 |
|
beckerjc@394
|
270 |
class ClassIt {
|
beckerjc@394
|
271 |
friend class UnionFindEnum;
|
beckerjc@394
|
272 |
|
beckerjc@394
|
273 |
CcIter i;
|
beckerjc@394
|
274 |
public:
|
beckerjc@394
|
275 |
ClassIt(Invalid): i(0) {}
|
beckerjc@394
|
276 |
ClassIt() {}
|
beckerjc@394
|
277 |
|
beckerjc@394
|
278 |
operator const T& () const {
|
beckerjc@394
|
279 |
ItemList const &ll = *i;
|
beckerjc@394
|
280 |
return (ll.begin())->me; }
|
beckerjc@394
|
281 |
bool operator == (ClassIt it) const {
|
beckerjc@394
|
282 |
return (i == it.i);
|
beckerjc@394
|
283 |
}
|
beckerjc@394
|
284 |
bool operator != (ClassIt it) const {
|
beckerjc@394
|
285 |
return (i != it.i);
|
beckerjc@394
|
286 |
}
|
beckerjc@394
|
287 |
bool operator < (ClassIt it) const {
|
beckerjc@394
|
288 |
return (i < it.i);
|
beckerjc@394
|
289 |
}
|
beckerjc@394
|
290 |
|
beckerjc@394
|
291 |
bool valid() const { return i != 0; }
|
beckerjc@394
|
292 |
private:
|
beckerjc@394
|
293 |
void first(const ClassList &l) { i = l.begin(); validate(l); }
|
beckerjc@394
|
294 |
void next(const ClassList &l) {
|
beckerjc@394
|
295 |
++i;
|
beckerjc@394
|
296 |
validate(l);
|
beckerjc@394
|
297 |
}
|
beckerjc@394
|
298 |
void validate(const ClassList &l) {
|
beckerjc@394
|
299 |
if ( i == l.end() )
|
beckerjc@394
|
300 |
i = 0;
|
beckerjc@394
|
301 |
}
|
beckerjc@394
|
302 |
};
|
beckerjc@394
|
303 |
|
beckerjc@394
|
304 |
|
beckerjc@394
|
305 |
ClassIt& first(ClassIt& it) const {
|
beckerjc@394
|
306 |
it.first(classes);
|
beckerjc@394
|
307 |
return it;
|
beckerjc@394
|
308 |
}
|
beckerjc@394
|
309 |
|
beckerjc@394
|
310 |
bool valid(ClassIt const &it) const {
|
beckerjc@394
|
311 |
return it.valid();
|
beckerjc@394
|
312 |
}
|
beckerjc@394
|
313 |
|
beckerjc@394
|
314 |
ClassIt& next(ClassIt& it) const {
|
beckerjc@394
|
315 |
it.next(classes);
|
beckerjc@394
|
316 |
return it;
|
beckerjc@394
|
317 |
}
|
beckerjc@394
|
318 |
|
beckerjc@394
|
319 |
|
beckerjc@394
|
320 |
class ItemIt {
|
beckerjc@394
|
321 |
friend class UnionFindEnum;
|
beckerjc@394
|
322 |
|
beckerjc@394
|
323 |
IcIter i;
|
beckerjc@394
|
324 |
const ItemList *l;
|
beckerjc@394
|
325 |
public:
|
beckerjc@394
|
326 |
ItemIt(Invalid): i(0) {}
|
beckerjc@394
|
327 |
ItemIt() {}
|
beckerjc@394
|
328 |
|
beckerjc@394
|
329 |
operator const T& () const { return i->me; }
|
beckerjc@394
|
330 |
bool operator == (ItemIt it) const {
|
beckerjc@394
|
331 |
return (i == it.i);
|
beckerjc@394
|
332 |
}
|
beckerjc@394
|
333 |
bool operator != (ItemIt it) const {
|
beckerjc@394
|
334 |
return (i != it.i);
|
beckerjc@394
|
335 |
}
|
beckerjc@394
|
336 |
bool operator < (ItemIt it) const {
|
beckerjc@394
|
337 |
return (i < it.i);
|
beckerjc@394
|
338 |
}
|
beckerjc@394
|
339 |
|
beckerjc@394
|
340 |
bool valid() const { return i != 0; }
|
beckerjc@394
|
341 |
private:
|
beckerjc@394
|
342 |
void first(const ItemList &il) { l=&il; i = l->begin(); validate(); }
|
beckerjc@394
|
343 |
void next() {
|
beckerjc@394
|
344 |
++i;
|
beckerjc@394
|
345 |
validate();
|
beckerjc@394
|
346 |
}
|
beckerjc@394
|
347 |
void validate() {
|
beckerjc@394
|
348 |
if ( i == l->end() )
|
beckerjc@394
|
349 |
i = 0;
|
beckerjc@394
|
350 |
}
|
beckerjc@394
|
351 |
};
|
beckerjc@394
|
352 |
|
beckerjc@394
|
353 |
|
beckerjc@394
|
354 |
ItemIt& first(ItemIt& it, const T& a) const {
|
beckerjc@394
|
355 |
it.first( * _find(m[a])->my_class );
|
beckerjc@394
|
356 |
return it;
|
beckerjc@394
|
357 |
}
|
beckerjc@394
|
358 |
|
beckerjc@394
|
359 |
bool valid(ItemIt const &it) const {
|
beckerjc@394
|
360 |
return it.valid();
|
beckerjc@394
|
361 |
}
|
beckerjc@394
|
362 |
|
beckerjc@394
|
363 |
ItemIt& next(ItemIt& it) const {
|
beckerjc@394
|
364 |
it.next();
|
beckerjc@394
|
365 |
return it;
|
beckerjc@394
|
366 |
}
|
beckerjc@394
|
367 |
|
beckerjc@394
|
368 |
|
beckerjc@394
|
369 |
|
beckerjc@394
|
370 |
};
|
beckerjc@394
|
371 |
|
beckerjc@150
|
372 |
} //namespace hugo
|
beckerjc@150
|
373 |
|
beckerjc@218
|
374 |
#endif //HUGO_UNION_FIND_H
|