Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
DisjointSets.h
Go to the documentation of this file.
1
32#pragma once
33
34#include <ogdf/basic/basic.h>
36
37#include <cstring>
38
39namespace ogdf {
40
41#define OGDF_DISJOINT_SETS_INTERMEDIATE_PARENT_CHECK
42
44enum class LinkOptions {
45 Naive = 0,
46 Index = 1,
47 Size = 2,
48 Rank = 3
49};
50
53 PathCompression = 0,
54 PathSplitting = 1,
55 PathHalving = 2,
56 Type1Reversal = 4,
57 Collapsing = 5,
58 Disabled = 6
59};
60
63 Disabled = 0,
64 Rem = 1,
65 Tarjan = 2,
66 Type0Reversal = 3,
68 4
69};
70
71namespace disjoint_sets {
72
73struct AnyOption { };
74
75template<LinkOptions linkOption>
76struct LinkOption : AnyOption { };
77
78template<CompressionOptions compressionOption>
80
81template<InterleavingOptions interleavingOption>
83
84}
85
87template<LinkOptions linkOption = LinkOptions::Index,
91 static_assert(interleavingOption != InterleavingOptions::Rem || linkOption == LinkOptions::Index,
92 "Rem's Algorithm requires linking by index.");
93 static_assert(interleavingOption != InterleavingOptions::Tarjan || linkOption == LinkOptions::Rank,
94 "Tarjan and van Leeuwen's Algorithm requires linking by rank.");
95 static_assert(interleavingOption != InterleavingOptions::Type0Reversal
96 || linkOption == LinkOptions::Naive,
97 "Interleaved Reversal Type 0 requires naïve linking.");
98 static_assert(interleavingOption != InterleavingOptions::SplittingCompression
99 || linkOption == LinkOptions::Index,
100 "Interleaved Path Splitting Path Compression requires linking by index.");
101
102private:
106
107 // Arrays parents, elements, parameters, siblings map a set id to its properties.
108
112
113 //find
120
121 //link
124 int link(disjoint_sets::LinkOption<LinkOptions::Size>, int set1, int set2);
125 int link(disjoint_sets::LinkOption<LinkOptions::Rank>, int set1, int set2);
126
127 //quickUnion
132 int set2);
139 int set2);
140
141public:
143
146 explicit DisjointSets(int maxNumberOfElements = (1 << 15))
147 : m_parents(nullptr), m_parameters(nullptr), m_siblings(nullptr) {
148 init(maxNumberOfElements);
149 }
150
152 delete[] this->m_parents;
153 delete[] this->m_parameters;
154 delete[] this->m_siblings;
155 }
156
159 m_numberOfElements = copy.m_numberOfElements;
160 if (copy.m_parents) {
161 std::copy_n(copy.m_parents, m_maxNumberOfElements, m_parents);
162 }
163 if (copy.m_parameters) {
164 std::copy_n(copy.m_parameters, m_maxNumberOfElements, m_parameters);
165 }
166 if (copy.m_siblings) {
167 std::copy_n(copy.m_siblings, m_maxNumberOfElements, m_siblings);
168 }
169 }
170
172 std::swap(first.m_numberOfSets, second.m_numberOfSets);
173 std::swap(first.m_numberOfElements, second.m_numberOfElements);
174 std::swap(first.m_maxNumberOfElements, second.m_maxNumberOfElements);
175 std::swap(first.m_parents, second.m_parents);
176 std::swap(first.m_parameters, second.m_parameters);
177 std::swap(first.m_siblings, second.m_siblings);
178 };
179
181
182
183 void init(int maxNumberOfElements) {
184 this->m_maxNumberOfElements = maxNumberOfElements;
185 init();
186 }
187
189 void init() {
190 delete[] this->m_parents;
191 delete[] this->m_parameters;
192 delete[] this->m_siblings;
193 this->m_numberOfSets = 0;
194 this->m_numberOfElements = 0;
195 this->m_parents = new int[this->m_maxNumberOfElements];
196 this->m_parameters = (linkOption == LinkOptions::Rank || linkOption == LinkOptions::Size)
197 ? new int[this->m_maxNumberOfElements]
198 : nullptr;
199 this->m_siblings = (compressionOption == CompressionOptions::Collapsing)
200 ? new int[this->m_maxNumberOfElements]
201 : nullptr;
202 }
203
205
210 int find(int set) {
211 OGDF_ASSERT(set >= 0);
214 }
215
217
222 int getRepresentative(int set) const {
223 OGDF_ASSERT(set >= 0);
225 while (set != m_parents[set]) {
226 set = m_parents[set];
227 }
228 return set;
229 }
230
232
235 int makeSet() {
236 if (this->m_numberOfElements == this->m_maxNumberOfElements) {
237 int* parents = this->m_parents;
238 this->m_parents = new int[this->m_maxNumberOfElements * 2];
239 memcpy(this->m_parents, parents, sizeof(int) * this->m_maxNumberOfElements);
240 delete[] parents;
241
242 if (this->m_parameters != nullptr) {
243 int* parameters = this->m_parameters;
244 this->m_parameters = new int[this->m_maxNumberOfElements * 2];
245 memcpy(this->m_parameters, parameters, sizeof(int) * this->m_maxNumberOfElements);
246 delete[] parameters;
247 }
248
249 if (this->m_siblings != nullptr) {
250 int* siblings = this->m_siblings;
251 this->m_siblings = new int[this->m_maxNumberOfElements * 2];
252 memcpy(this->m_siblings, siblings, sizeof(int) * this->m_maxNumberOfElements);
253 delete[] siblings;
254 }
255 this->m_maxNumberOfElements *= 2;
256 }
257 this->m_numberOfSets++;
258 int id = this->m_numberOfElements++;
259 this->m_parents[id] = id;
260 //Initialize size/ rank/ sibling.
261 if (linkOption == LinkOptions::Size) {
262 this->m_parameters[id] = 1;
263 } else if (linkOption == LinkOptions::Rank) {
264 this->m_parameters[id] = 0;
265 }
266 if (compressionOption == CompressionOptions::Collapsing) {
267 this->m_siblings[id] = -1;
268 }
269 return id;
270 }
271
273
277 int link(int set1, int set2) {
278 OGDF_ASSERT(set1 == getRepresentative(set1));
279 OGDF_ASSERT(set2 == getRepresentative(set2));
280 if (set1 == set2) {
281 return -1;
282 }
283 this->m_numberOfSets--;
284 return linkPure(set1, set2);
285 }
286
288
291 bool quickUnion(int set1, int set2) {
292 if (set1 == set2) {
293 return false;
294 }
297 m_numberOfSets -= result;
298 return result;
299 }
300
303
306
307private:
309
313 int linkPure(int set1, int set2) {
314 int superset = link(disjoint_sets::LinkOption<linkOption>(), set1, set2);
315 //Collapse subset tree.
316 if (compressionOption == CompressionOptions::Collapsing) {
317 int subset = set1 == superset ? set2 : set1;
318 int id = subset;
319 while (this->m_siblings[id] != -1) {
320 id = this->m_siblings[id];
321 this->m_parents[id] = superset;
322 }
323 this->m_siblings[id] = this->m_siblings[superset];
324 this->m_siblings[superset] = subset;
325 }
326 return superset;
327 }
328};
329
330//find
331template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
334 int parent = m_parents[set];
335 if (set == parent) {
336 return set;
337 } else {
339 parent);
340 m_parents[set] = parent;
341 return parent;
342 }
343}
344
345template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
348 while (set != m_parents[set]) {
349 int parent = m_parents[set];
350 int grandParent = m_parents[parent];
351 m_parents[set] = grandParent;
352 set = grandParent;
353 }
354 return set;
355}
356
357template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
360 int parent = m_parents[set];
361 int grandParent = m_parents[parent];
362 while (parent != grandParent) {
363 m_parents[set] = grandParent;
364 set = parent;
365 parent = grandParent;
366 grandParent = m_parents[grandParent];
367 }
368 return parent;
369}
370
371template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
374 int root = set;
375 set = m_parents[root];
376
377 while (set != m_parents[set]) {
378 int parent = m_parents[set];
379 m_parents[set] = root;
380 set = parent;
381 }
382 m_parents[root] = set;
383 return set;
384}
385
386template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
389 while (set != m_parents[set]) {
390 set = m_parents[set];
391 }
392 return set;
393}
394
395template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
400
401//quickUnion
402template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
405 int set1, int set2) {
406#ifdef OGDF_DISJOINT_SETS_INTERMEDIATE_PARENT_CHECK
407 if (m_parents[set1] == m_parents[set2]) {
408 return false;
409 }
410#endif
411 set1 = find(set1);
412 set2 = find(set2);
413 if (set1 != set2) {
414 linkPure(set1, set2);
415 return true;
416 }
417 return false;
418}
419
420template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
424#ifdef OGDF_DISJOINT_SETS_INTERMEDIATE_PARENT_CHECK
425 if (m_parents[set1] == m_parents[set2]) {
426 return false;
427 }
428#endif
429 int root = set2;
430 int set = set2;
431 int parent = m_parents[set];
432 m_parents[set] = root;
433 while (set != parent) {
434 if (parent == set1) {
435 m_parents[root] = set1;
436 return false;
437 }
438 set = parent;
439 parent = m_parents[set];
440 m_parents[set] = root;
441 }
442
443 set = set1;
444 parent = m_parents[set];
445 while (true) {
446 if (parent == root) {
447 return false;
448 }
449 m_parents[set] = root;
450 if (parent == set) {
451 return true;
452 }
453 set = parent;
454 parent = m_parents[set];
455 }
456}
457
458template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
462 int r_x = set1;
463 int r_y = set2;
464 int p_r_x = m_parents[r_x];
465 int p_r_y = m_parents[r_y];
466 while (p_r_x != p_r_y) {
467 if (p_r_x < p_r_y) {
468 if (r_x == p_r_x) {
469 m_parents[r_x] = p_r_y;
470 return true;
471 }
472 m_parents[r_x] = p_r_y;
473 r_x = p_r_x;
474 p_r_x = m_parents[r_x];
475 } else {
476 if (r_y == p_r_y) {
477 m_parents[r_y] = p_r_x;
478 return true;
479 }
480 m_parents[r_y] = p_r_x;
481 r_y = p_r_y;
482 p_r_y = m_parents[r_y];
483 }
484 }
485 return false;
486}
487
488template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
492 int set2) {
493#ifdef OGDF_DISJOINT_SETS_INTERMEDIATE_PARENT_CHECK
494 if (m_parents[set1] == m_parents[set2]) {
495 return false;
496 }
497#endif
498 int set = set1;
499
500 if (set1 < set2) {
501 set = set2;
502 set2 = set1;
503 set1 = set;
504 }
505
507 set = m_parents[set];
508 int parent = m_parents[set];
509 int grandParent = m_parents[parent];
510 while (parent != grandParent) {
511 m_parents[set] = grandParent;
512 set = parent;
513 parent = grandParent;
514 grandParent = m_parents[grandParent];
515 }
516 m_parents[set1] = parent;
517 int root = parent;
518
520 set = set2;
521 parent = m_parents[set];
522 while (true) {
523 if (parent < root) {
524 m_parents[set] = root;
525 if (set == parent) {
526 return true;
527 }
528 set = parent;
529 parent = m_parents[set];
530 } else if (parent > root) {
531 m_parents[root] = parent;
532 m_parents[set1] = parent;
533 m_parents[set2] = parent;
534 return true;
535 } else {
536 return false;
537 }
538 }
539}
540
541template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
545 int r_x = set1;
546 int r_y = set2;
547 int p_r_x = m_parents[r_x];
548 int p_r_y = m_parents[r_y];
549 while (p_r_x != p_r_y) {
550 if (m_parameters[p_r_x] <= m_parameters[p_r_y]) {
551 if (r_x == p_r_x) {
552 if (m_parameters[p_r_x] == m_parameters[p_r_y] && p_r_y == m_parents[p_r_y]) {
553 m_parameters[p_r_y]++;
554 }
555 m_parents[r_x] = m_parents[p_r_y];
556 return true;
557 }
558 m_parents[r_x] = p_r_y;
559 r_x = p_r_x;
560 p_r_x = m_parents[r_x];
561 } else {
562 if (r_y == p_r_y) {
563 m_parents[r_y] = m_parents[p_r_x];
564 return true;
565 }
566 m_parents[r_y] = p_r_x;
567 r_y = p_r_y;
568 p_r_y = m_parents[r_y];
569 }
570 }
571 return false;
572}
573
574//link
575template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
578 if (set1 < set2) {
579 m_parents[set1] = set2;
580 return set2;
581 } else {
582 m_parents[set2] = set1;
583 return set1;
584 }
585}
586
587template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
590 int parameter1 = m_parameters[set1];
591 int parameter2 = m_parameters[set2];
592
593 if (parameter1 < parameter2) {
594 m_parents[set1] = set2;
595 return set2;
596 } else if (parameter1 > parameter2) {
597 m_parents[set2] = set1;
598 return set1;
599 } else {
600 m_parents[set1] = set2;
601 m_parameters[set2]++;
602 return set2;
603 }
604}
605
606template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
609 int parameter1 = m_parameters[set1];
610 int parameter2 = m_parameters[set2];
611
612 if (parameter1 < parameter2) {
613 m_parents[set1] = set2;
614 m_parameters[set2] += parameter1;
615 return set2;
616 } else {
617 m_parents[set2] = set1;
618 m_parameters[set1] += parameter2;
619 return set1;
620 }
621}
622
623template<LinkOptions linkOption, CompressionOptions compressionOption, InterleavingOptions interleavingOption>
626 m_parents[set1] = set2;
627 return set2;
628}
629
630}
Basic declarations, included by all source files.
A Union/Find data structure for maintaining disjoint sets.
bool quickUnion(int set1, int set2)
Unions the maximal disjoint sets containing set1 and set2.
int makeSet()
Initializes a singleton set.
int getRepresentative(int set) const
Returns the id of the largest superset of set.
void init()
Resets the DisjointSets structure to be empty, preserving the previous value of maxNumberOfElements.
int m_numberOfElements
Current number of elements.
bool quickUnion(disjoint_sets::LinkOption< LinkOptions::Index >, disjoint_sets::InterleavingOption< InterleavingOptions::Rem >, int set1, int set2)
int find(int set)
Returns the id of the largest superset of set and compresses the path according to CompressionOptions...
int m_numberOfSets
Current number of disjoint sets.
int getNumberOfSets()
Returns the current number of disjoint sets.
int find(disjoint_sets::CompressionOption< CompressionOptions::PathCompression >, int set)
int link(disjoint_sets::LinkOption< LinkOptions::Naive >, int set1, int set2)
DisjointSets(int maxNumberOfElements=(1<< 15))
Creates an empty DisjointSets structure.
int * m_parameters
Maps set id to rank/size.
int getNumberOfElements()
Returns the current number of elements.
int * m_parents
Maps set id to parent set id.
int link(int set1, int set2)
Unions set1 and set2.
int linkPure(int set1, int set2)
Unions set1 and set2 w/o decreasing the numberOfSets.
int * m_siblings
Maps set id to sibling set id.
int m_maxNumberOfElements
Maximum number of elements (array size) adjusted dynamically.
Utility macros for declaring copy and move constructors and assignment operations.
#define OGDF_COPY_CONSTR(cls)
Declares the copy constructor for class cls.
Definition copy_move.h:57
#define OGDF_SWAP_OP(cls)
Declares the swap function for class cls.
Definition copy_move.h:65
#define OGDF_COPY_MOVE_BY_SWAP(cls)
Provide move construct/assign and copy assign given there is a copy constructor and swap.
Definition copy_move.h:76
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:52
The namespace for all OGDF objects.
LinkOptions
Defines options for linking two sets.
@ Rank
Link by rank.
@ Naive
Naive Link.
@ Size
Link by size.
@ Index
Link by index (default)
InterleavingOptions
Defines options for interleaving find/link operations in quickUnion.
@ Type0Reversal
Interleaved Reversal of Type 0 (only compatible with LinkOptions::Naive)
@ SplittingCompression
Interleaved Path Splitting Path Compression (only compatible with LinkOptions::Index)
@ Tarjan
Tarjan's and van Leeuwen's Algorithm (only compatible with LinkOptions::Rank)
@ Disabled
No Interleaving (default)
@ Rem
Rem's Algorithm (only compatible with LinkOptions::Index)
CompressionOptions
Defines options for compression search paths.
@ PathHalving
Path Halving.
@ PathSplitting
Path Splitting (default)
@ Disabled
No Compression.
@ Type1Reversal
Reversal of type 1.
@ PathCompression
Path Compression.