Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
union.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
38#include <gtest/gtest.h>
39
40#include <tpl_union.H>
41
42#include <random>
43#include <string>
44#include <vector>
45
46using namespace std;
47
48namespace {
49
50class FixedRelationInspector : public Fixed_Relation
51{
52public:
57};
58
59struct RefDsu
60{
61 vector<size_t> parent;
62 vector<size_t> sz;
63 size_t blocks = 0;
64
65 explicit RefDsu(size_t n) : parent(n), sz(n, 1), blocks(n)
66 {
67 for (size_t i = 0; i < n; ++i)
68 parent[i] = i;
69 }
70
71 void ensure(size_t n)
72 {
73 if (n <= parent.size())
74 return;
75
76 const size_t old = parent.size();
77 parent.resize(n);
78 sz.resize(n, 1);
79 for (size_t i = old; i < n; ++i)
80 parent[i] = i;
81 blocks += n - old;
82 }
83
84 size_t find(size_t x)
85 {
86 while (x != parent[x])
87 {
88 parent[x] = parent[parent[x]];
89 x = parent[x];
90 }
91 return x;
92 }
93
94 bool connected(size_t a, size_t b)
95 {
96 return find(a) == find(b);
97 }
98
99 void unite(size_t a, size_t b)
100 {
101 a = find(a);
102 b = find(b);
103 if (a == b)
104 return;
105
106 if (sz[a] < sz[b])
107 {
108 parent[a] = b;
109 sz[b] += sz[a];
110 }
111 else
112 {
113 parent[b] = a;
114 sz[a] += sz[b];
115 }
116
117 --blocks;
118 }
119};
120
122{
124 EXPECT_EQ(rel.size(), 0u);
125 EXPECT_EQ(rel.get_num_blocks(), 0u);
126 EXPECT_THROW(rel.are_connected(0, 0), std::out_of_range);
127 EXPECT_THROW(rel.join(0, 0), std::out_of_range);
128}
129
131{
133 EXPECT_EQ(rel.size(), 5u);
134 EXPECT_EQ(rel.get_num_blocks(), 5u);
135
136 EXPECT_TRUE(rel.are_connected(0, 0));
137 EXPECT_FALSE(rel.are_connected(0, 1));
138
139 rel.join(0, 1);
140 EXPECT_TRUE(rel.are_connected(0, 1));
141 EXPECT_EQ(rel.get_num_blocks(), 4u);
142
143 rel.join(1, 2);
144 EXPECT_TRUE(rel.are_connected(0, 2));
145 EXPECT_EQ(rel.get_num_blocks(), 3u);
146
147 const size_t before = rel.get_num_blocks();
148 rel.join(0, 2);
149 EXPECT_EQ(rel.get_num_blocks(), before);
150
151 EXPECT_THROW(rel.are_connected(0, 5), std::out_of_range);
152 EXPECT_THROW(rel.join(4, 5), std::out_of_range);
153}
154
156{
158 rel.join(0, 1);
159 EXPECT_TRUE(rel.are_connected(0, 1));
160 EXPECT_EQ(rel.get_num_blocks(), 3u);
161
162 rel.set_n(2);
163 EXPECT_EQ(rel.size(), 2u);
164 EXPECT_EQ(rel.get_num_blocks(), 2u);
165 EXPECT_FALSE(rel.are_connected(0, 1));
166 EXPECT_THROW(rel.are_connected(0, 2), std::out_of_range);
167}
168
170{
171 {
172 FixedRelationInspector rel(3);
173 rel.id(0) = 1;
174 rel.id(1) = 0;
175 rel.id(2) = 2;
176 EXPECT_THROW(rel.depth(0), std::logic_error);
177 }
178
179 {
180 FixedRelationInspector rel(3);
181 rel.id(0) = 10;
182 EXPECT_THROW(rel.depth(0), std::out_of_range);
183 }
184}
185
187{
188 constexpr size_t n = 50;
190 RefDsu ref(n);
191
192 std::mt19937 rng(1);
193 std::uniform_int_distribution<size_t> pick(0, n - 1);
194
195 for (int step = 0; step < 2000; ++step)
196 {
197 const size_t a = pick(rng);
198 const size_t b = pick(rng);
199
200 if (step % 3 == 0)
201 {
202 EXPECT_EQ(rel.are_connected(a, b), ref.connected(a, b));
203 }
204 else
205 {
206 rel.join(a, b);
207 ref.unite(a, b);
208 EXPECT_EQ(rel.get_num_blocks(), ref.blocks);
209 }
210 }
211}
212
214{
216 EXPECT_EQ(rel.size(), 0u);
217 EXPECT_EQ(rel.get_num_blocks(), 0u);
218
219 EXPECT_TRUE(rel.are_connected(0, 0));
220 EXPECT_EQ(rel.size(), 1u);
221 EXPECT_EQ(rel.get_num_blocks(), 1u);
222
223 EXPECT_FALSE(rel.are_connected(0, 1));
224 EXPECT_EQ(rel.size(), 2u);
225 EXPECT_EQ(rel.get_num_blocks(), 2u);
226
227 rel.join(0, 1);
228 EXPECT_TRUE(rel.are_connected(0, 1));
229 EXPECT_EQ(rel.size(), 2u);
230 EXPECT_EQ(rel.get_num_blocks(), 1u);
231
232 EXPECT_TRUE(rel.are_connected(100, 100));
233 EXPECT_EQ(rel.size(), 101u);
234 EXPECT_EQ(rel.get_num_blocks(), 100u);
235
236 EXPECT_FALSE(rel.are_connected(100, 0));
237}
238
240{
242 RefDsu ref(0);
243
244 std::mt19937 rng(2);
245 std::uniform_int_distribution<size_t> pick(0, 200);
246
247 for (int step = 0; step < 1500; ++step)
248 {
249 const size_t a = pick(rng);
250 const size_t b = pick(rng);
251
252 ref.ensure(std::max(a, b) + 1);
253
254 if (step % 4 == 0)
255 {
256 EXPECT_EQ(rel.are_connected(a, b), ref.connected(a, b));
257 EXPECT_EQ(rel.size(), ref.parent.size());
258 EXPECT_EQ(rel.get_num_blocks(), ref.blocks);
259 }
260 else
261 {
262 rel.join(a, b);
263 ref.unite(a, b);
264 EXPECT_EQ(rel.size(), ref.parent.size());
265 EXPECT_EQ(rel.get_num_blocks(), ref.blocks);
266 }
267 }
268}
269
271{
273
274 EXPECT_TRUE(rel.are_connected(1, 1));
275 EXPECT_EQ(rel.size(), 1u);
276 EXPECT_EQ(rel.get_num_blocks(), 1u);
277
278 EXPECT_FALSE(rel.are_connected(1, 2));
279 EXPECT_EQ(rel.size(), 2u);
280 EXPECT_EQ(rel.get_num_blocks(), 2u);
281
282 rel.join(1, 2);
283 EXPECT_TRUE(rel.are_connected(1, 2));
284 EXPECT_EQ(rel.get_num_blocks(), 1u);
285
286 const size_t size_before = rel.size();
287 const size_t blocks_before = rel.get_num_blocks();
288 EXPECT_TRUE(rel.are_connected(2, 1));
290 EXPECT_EQ(rel.get_num_blocks(), blocks_before);
291}
292
294{
296
297 EXPECT_FALSE(rel.are_connected(std::string("a"), std::string("b")));
298 EXPECT_EQ(rel.size(), 2u);
299 EXPECT_EQ(rel.get_num_blocks(), 2u);
300
301 rel.join(std::string("a"), std::string("b"));
302 EXPECT_TRUE(rel.are_connected(std::string("a"), std::string("b")));
303 EXPECT_EQ(rel.get_num_blocks(), 1u);
304
305 EXPECT_FALSE(rel.are_connected(std::string("c"), std::string("a")));
306 EXPECT_EQ(rel.size(), 3u);
307 EXPECT_EQ(rel.get_num_blocks(), 2u);
308}
309
310} // namespace
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Binary relation between a set of integers.
Definition tpl_union.H:82
Fixed_Relation(const size_t n=0)
Initialize an empty binary relation of integers between 0 and n - 1.
Definition tpl_union.H:127
virtual size_t root(size_t i)
Definition tpl_union.H:93
DynArray< size_t > id
Definition tpl_union.H:84
size_t depth(size_t i) const
Definition tpl_union.H:105
Binary relation between a set of items.
Definition tpl_union.H:286
Binary relation between a set of integers.
Definition tpl_union.H:239
#define TEST(name)
static mt19937 rng
Itor find(const Itor &beg, const Itor &end, const T &value)
Find the first element equal to a value.
Definition ahAlgo.H:230
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
Union-Find (Disjoint Set Union) data structure.