-
Notifications
You must be signed in to change notification settings - Fork 0
/
UnionFind.h
143 lines (124 loc) · 3.46 KB
/
UnionFind.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#ifndef UNIONFIND_H
#define UNIONFIND_H
#include <iostream>
#include <vector>
#include <cmath>
// Define an enum for the types
enum PathCompressionType { NC, FC, PS, PH };
struct Measure {
int tpl;
int tpu;
};
class UnionFind {
protected:
std::vector<int> P;
int n_blocks;
PathCompressionType pathCompressionType;
public:
// Default constructor
UnionFind() : n_blocks(0) {}
// Virtual destructor
virtual ~UnionFind() {}
// Returns the representative of the class to which i belongs
virtual int find(int i) {
if (P[i] == i || P[i] < 0) return i;
//no compression
if (pathCompressionType == NC) {
return find(P[i]);;
}
//full path compression: Make every node point to its representative.
else if (pathCompressionType == FC) {
P[i] = find(P[i]);
return P[i];
}
//path splitting: Make every node point to its grandparent (except if it is the root or a child of the root).
else if (pathCompressionType == PS) {
int child = -1;
int grandchild = -1;
while (!(P[i] == i || P[i] < 0)) {
if (grandchild != -1) {
P[grandchild] = i;
}
grandchild = child;
child = i;
i = P[i];
}
return i;
}
//path halving: Make every other node in the path point to its grandparent (except if it is the root or a child of the root).
else if (pathCompressionType == PH) {
int distance = 0; // Distance from the root
int grandchild = i;
while (!(P[i] == i || P[i] < 0)) {
if (distance == 2) {
P[grandchild] = i;
distance = 0;
grandchild = i;
}
++distance;
i = P[i];
}
return i;
}
else {
std::cerr << "Invalid path compression pathCompressionType" << std::endl;
return -1;
}
}
// Performs the union of the classes with representatives ri and rj
virtual void merge(int i, int j) = 0;
// Returns the number of blocks in the union-find set
virtual int nr_blocks() const {
return n_blocks;
};
virtual std::vector<int> Parents() const {
return P;
}
// Function to calculate path length from node i to its root
int pathLength(int i) {
int length = 0;
while (!(P[i] == i || P[i] < 0)) {
length++;
i = P[i];
}
return length;
}
Measure calculateTPL() {
int tpl = 0;
int tpu = 0;
for (int i = 0; i < P.size(); ++i) {
int const pl = pathLength(i);
int pu = 0;
//no compression
if (pathCompressionType == NC) {
pu = 0;
}
//full path compression: Make every node point to its representative.
//path splitting: Make every node point to its grandparent (except if it is the root or a child of the root).
else if (pathCompressionType == FC || pathCompressionType == PS) {
pu = pl > 0 ? pl - 1 : 0;
}
//path halving: Make every other node in the path point to its grandparent (except if it is the root or a child of the root).
else if (pathCompressionType == PH) {
pu = floor(pl / 2);
}
else {
std::cerr << "Invalid path compression pathCompressionType" << std::endl;
}
tpl += pl;
tpu += pu;
}
Measure measure = { tpl, tpu };
return measure;
}
// Default implementation of print
virtual void print() {
std::cout << "[ ";
for (int num : P) {
std::cout << num << " ";
}
std::cout << "]; ";
std::cout << std::endl;
}
};
#endif // UNIONFIND_H