Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
union_find_example.C
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
184#include <iostream>
185#include <string>
186#include <vector>
187#include <tpl_union.H>
188
189using namespace std;
190using namespace Aleph;
191
192// =============================================================================
193// Example 1: Basic Union-Find Operations
194// =============================================================================
195
197{
198 cout << "\n";
199 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
200 cout << "║ EXAMPLE 1: Basic Union-Find Operations ║\n";
201 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
202
203 // Fixed_Relation: For elements identified by integers 0..n-1
204 const size_t n = 10;
205 Fixed_Relation uf(n);
206
207 cout << "Created Union-Find with " << n << " elements (0 to 9)\n";
208 cout << "Initially, each element is in its own singleton set.\n\n";
209
210 // Show initial state - demonstrate which elements are connected
211 cout << "Initial state: Each element is isolated in its own set.\n";
212 cout << "Number of disjoint sets: " << uf.get_num_blocks() << "\n";
213
214 cout << "\n--- Performing unions ---\n\n";
215
216 // Union some sets
217 cout << "join(0, 1): Merge sets containing 0 and 1\n";
218 uf.join(0, 1);
219
220 cout << "join(2, 3): Merge sets containing 2 and 3\n";
221 uf.join(2, 3);
222
223 cout << "join(4, 5): Merge sets containing 4 and 5\n";
224 uf.join(4, 5);
225
226 cout << "join(0, 2): Merge sets {0,1} and {2,3} into {0,1,2,3}\n";
227 uf.join(0, 2);
228
229 cout << "\n--- Checking connectivity ---\n\n";
230
231 // Check if elements are in the same set
232 auto check = [&uf](size_t a, size_t b) {
233 bool same = uf.are_connected(a, b);
234 cout << " " << a << " and " << b << " are "
235 << (same ? "in the SAME set" : "in DIFFERENT sets") << "\n";
236 };
237
238 cout << "Connectivity queries:\n";
239 check(0, 3); // Should be same (both in {0,1,2,3})
240 check(4, 5); // Should be same (both in {4,5})
241 check(1, 4); // Should be different
242 check(6, 7); // Should be different (both singletons)
243
244 cout << "\n--- Final state ---\n\n";
245
246 // Show connectivity relationships
247 cout << "Elements in same set as 0: ";
248 for (size_t i = 0; i < n; ++i)
249 if (uf.are_connected(0, i))
250 cout << i << " ";
251 cout << "\n";
252
253 cout << "Elements in same set as 4: ";
254 for (size_t i = 0; i < n; ++i)
255 if (uf.are_connected(4, i))
256 cout << i << " ";
257 cout << "\n";
258
259 cout << "\nNumber of disjoint sets: " << uf.get_num_blocks() << "\n";
260}
261
262// =============================================================================
263// Example 2: Network Connectivity Problem
264// =============================================================================
265
267{
268 cout << "\n";
269 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
270 cout << "║ EXAMPLE 2: Network Connectivity Problem ║\n";
271 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
272
273 cout << "Problem: A network has 8 computers. Given a list of direct\n";
274 cout << "connections, determine which computers can communicate.\n\n";
275
276 const size_t num_computers = 8;
278
279 // Network topology (direct connections)
281 {0, 1}, {1, 2}, // Computers 0-1-2 connected
282 {3, 4}, {4, 5}, {5, 3}, // Computers 3-4-5 connected (triangle)
283 {6, 7} // Computers 6-7 connected
284 };
285
286 cout << "Network topology (direct connections):\n";
287 cout << " Cluster A: 0 — 1 — 2\n";
288 cout << " Cluster B: 3 — 4 — 5 (triangle)\n";
289 cout << " Cluster C: 6 — 7\n";
290 cout << " Isolated: (none)\n\n";
291
292 // Add connections
293 cout << "Adding connections:\n";
294 for (auto& [a, b] : connections) {
295 cout << " Connect " << a << " ↔ " << b << "\n";
296 network.join(a, b);
297 }
298
299 cout << "\n--- Communication queries ---\n\n";
300
301 auto can_communicate = [&](size_t a, size_t b) {
302 bool can = network.are_connected(a, b);
303 cout << " Computer " << a << " and " << b << ": "
304 << (can ? "✓ CAN communicate" : "✗ CANNOT communicate") << "\n";
305 };
306
307 cout << "Testing if computers can communicate:\n";
308 can_communicate(0, 2); // Yes (same cluster)
309 can_communicate(3, 5); // Yes (same cluster)
310 can_communicate(0, 3); // No (different clusters)
311 can_communicate(6, 7); // Yes (same cluster)
312 can_communicate(2, 6); // No (different clusters)
313
314 cout << "\n--- Adding a bridge connection ---\n\n";
315
316 cout << "Adding connection 2 ↔ 3 (bridges Cluster A and B)\n";
317 network.join(2, 3);
318
319 cout << "\nUpdated connectivity:\n";
320 can_communicate(0, 5); // Now yes!
321 can_communicate(1, 4); // Now yes!
322
323 cout << "\nTotal isolated networks: " << network.size() << "\n";
324}
325
326// =============================================================================
327// Example 3: Kruskal's MST (Simplified)
328// =============================================================================
329
330struct Edge {
331 size_t u, v;
332 double weight;
333
334 bool operator<(const Edge& other) const {
335 return weight < other.weight;
336 }
337};
338
340{
341 cout << "\n";
342 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
343 cout << "║ EXAMPLE 3: Kruskal's MST Algorithm Simulation ║\n";
344 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
345
346 cout << "Kruskal's algorithm finds the Minimum Spanning Tree by:\n";
347 cout << " 1. Sort edges by weight\n";
348 cout << " 2. For each edge (u,v): add to MST if u,v in different sets\n";
349 cout << " 3. Union-Find tracks which vertices are connected\n\n";
350
351 // Graph with 6 vertices
352 const size_t V = 6;
353
354 // Edges: (u, v, weight)
356 {0, 1, 4.0}, {0, 2, 2.0}, {1, 2, 1.0}, {1, 3, 5.0},
357 {2, 3, 8.0}, {2, 4, 10.0}, {3, 4, 2.0}, {3, 5, 6.0}, {4, 5, 3.0}
358 };
359
360 cout << "Graph edges:\n";
361 for (const auto& e : edges)
362 cout << " " << e.u << " —(" << e.weight << ")— " << e.v << "\n";
363
364 // Sort edges by weight
365 sort(edges.begin(), edges.end());
366
367 cout << "\nSorted edges by weight:\n";
368 for (const auto& e : edges)
369 cout << " " << e.u << " —(" << e.weight << ")— " << e.v << "\n";
370
371 // Kruskal's algorithm using Union-Find
372 Fixed_Relation uf(V);
374 double total_weight = 0;
375
376 cout << "\n--- Running Kruskal's algorithm ---\n\n";
377
378 for (const auto& e : edges) {
379 if (!uf.are_connected(e.u, e.v)) {
380 cout << " ADD edge " << e.u << " —(" << e.weight << ")— " << e.v
381 << " (connects different components)\n";
382 uf.join(e.u, e.v);
383 mst.push_back(e);
384 total_weight += e.weight;
385 } else {
386 cout << " SKIP edge " << e.u << " —(" << e.weight << ")— " << e.v
387 << " (would create cycle)\n";
388 }
389
390 // MST has V-1 edges
391 if (mst.size() == V - 1)
392 break;
393 }
394
395 cout << "\n--- Minimum Spanning Tree ---\n\n";
396 cout << "MST edges:\n";
397 for (const auto& e : mst)
398 cout << " " << e.u << " —(" << e.weight << ")— " << e.v << "\n";
399 cout << "\nTotal MST weight: " << total_weight << "\n";
400}
401
402// =============================================================================
403// Example 4: Path Compression Visualization
404// =============================================================================
405
407{
408 cout << "\n";
409 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
410 cout << "║ EXAMPLE 4: Path Compression Effect ║\n";
411 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
412
413 cout << "Path compression flattens the tree during find operations,\n";
414 cout << "making subsequent finds much faster.\n\n";
415
416 const size_t n = 8;
417 Fixed_Relation uf(n);
418
419 // Create a chain structure by sequential unions
420 cout << "Creating connected components by sequential unions:\n";
421 for (size_t i = 0; i < n - 1; ++i) {
422 cout << " join(" << i << ", " << (i + 1) << ")\n";
423 uf.join(i, i + 1);
424 }
425
426 cout << "\nAfter all joins:\n";
427 cout << " All elements 0-" << (n-1) << " are now in the same set.\n";
428 cout << " Number of sets: " << uf.get_num_blocks() << "\n";
429
430 cout << "\nVerifying all elements are connected:\n";
431 for (size_t i = 1; i < n; ++i) {
432 bool conn = uf.are_connected(0, i);
433 cout << " 0 connected to " << i << ": " << (conn ? "YES" : "NO") << "\n";
434 }
435
436 cout << "\nPath compression happens automatically during are_connected().\n";
437 cout << "The internal tree structure is flattened, making future\n";
438 cout << "operations nearly O(1) - this is the key to Union-Find's speed!\n";
439}
440
441// =============================================================================
442// Main
443// =============================================================================
444
445int main()
446{
447 cout << "\n";
448 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
449 cout << "║ UNION-FIND (Disjoint Set Union) Data Structure Demo ║\n";
450 cout << "║ ║\n";
451 cout << "║ Aleph-w Library - https://github.com/lrleon/Aleph-w ║\n";
452 cout << "╚══════════════════════════════════════════════════════════════════╝\n";
453
458
459 cout << "\n";
460 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
461 cout << "║ Summary ║\n";
462 cout << "╠══════════════════════════════════════════════════════════════════╣\n";
463 cout << "║ Union-Find is one of the most elegant data structures: ║\n";
464 cout << "║ ║\n";
465 cout << "║ • Nearly O(1) operations via union-by-rank & path compression ║\n";
466 cout << "║ • Essential for Kruskal's MST algorithm ║\n";
467 cout << "║ • Used in network connectivity, image processing, and more ║\n";
468 cout << "║ ║\n";
469 cout << "║ Aleph-w provides Fixed_Relation for integer elements and ║\n";
470 cout << "║ Relation for arbitrary types with hash-based element lookup. ║\n";
471 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
472
473 return 0;
474}
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
constexpr size_t get_num_blocks() const noexcept
Return the number of connected blocks, which is the number of equivalence classes.
Definition tpl_union.H:173
void join(size_t i, size_t j)
Insert the pair '(i,j)' in the relation.
Definition tpl_union.H:198
bool are_connected(size_t i, size_t j)
Return true if item i is related to item j.
Definition tpl_union.H:187
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynArray< T > sort(const DynArray< T > &a, Cmp &&cmp=Cmp())
Returns a sorted copy of a DynArray.
Definition ahSort.H:227
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
double weight
bool operator<(const Edge &other) const
Union-Find (Disjoint Set Union) data structure.
void demo_network_connectivity()
void demo_basic_operations()
void demo_kruskal_simulation()
void demo_path_compression()
int main()