1+ /*
2+ * disjoint_union_set_test.cpp
3+ *
4+ * Created on: Dec 09, 2025 22:08
5+ * Description:
6+ *
7+ * Copyright (c) 2025 Pin Loon Lee (pllee4)
8+ */
9+
10+ #include " algorithm/generic/disjoint_union_set/disjoint_union_set.hpp"
11+
12+ #include " gtest/gtest.h"
13+
14+ using namespace pllee4 ::generic;
15+
16+ TEST (DisjointUnionSetsTest, InitialState) {
17+ DisjointUnionSets dsu (5 );
18+
19+ for (auto i = 0 ; i < 5 ; ++i) {
20+ EXPECT_EQ (dsu.Find (i), i)
21+ << " Element " << i << " should be its own parent initially" ;
22+ }
23+ }
24+
25+ TEST (DisjointUnionSetsTest, UnionTwoElements) {
26+ DisjointUnionSets dsu (5 );
27+
28+ dsu.UnionSets (0 , 1 );
29+
30+ EXPECT_EQ (dsu.Find (0 ), dsu.Find (1 ))
31+ << " Elements 0 and 1 should have the same root" ;
32+ }
33+
34+ TEST (DisjointUnionSetsTest, UnionChain) {
35+ DisjointUnionSets dsu (5 );
36+
37+ dsu.UnionSets (0 , 1 );
38+ dsu.UnionSets (1 , 2 );
39+ dsu.UnionSets (2 , 3 );
40+
41+ const auto root = dsu.Find (0 );
42+ EXPECT_EQ (dsu.Find (1 ), root);
43+ EXPECT_EQ (dsu.Find (2 ), root);
44+ EXPECT_EQ (dsu.Find (3 ), root);
45+ EXPECT_NE (dsu.Find (4 ), root) << " Element 4 should not be in the same set" ;
46+ }
47+
48+ TEST (DisjointUnionSetsTest, PathCompression) {
49+ DisjointUnionSets dsu (5 );
50+
51+ dsu.UnionSets (0 , 1 );
52+ dsu.UnionSets (1 , 2 );
53+ dsu.UnionSets (2 , 3 );
54+
55+ // After first Find, path should be compressed
56+ const auto root = dsu.Find (3 );
57+ EXPECT_EQ (dsu.Find (0 ), root);
58+
59+ // All elements should now point directly to root (path compression)
60+ EXPECT_EQ (dsu.Find (1 ), root);
61+ EXPECT_EQ (dsu.Find (2 ), root);
62+ }
63+
64+ TEST (DisjointUnionSetsTest, UnionByRank) {
65+ DisjointUnionSets dsu (10 );
66+
67+ // Create two trees of different ranks
68+ dsu.UnionSets (0 , 1 );
69+ dsu.UnionSets (2 , 3 );
70+ dsu.UnionSets (3 , 4 );
71+
72+ EXPECT_NE (dsu.Find (0 ), dsu.Find (2 ));
73+
74+ // Union the two trees
75+ dsu.UnionSets (0 , 2 );
76+
77+ // The tree with higher rank should become the root
78+ EXPECT_EQ (dsu.Find (4 ), dsu.Find (0 ));
79+ }
80+
81+ TEST (DisjointUnionSetsTest, SelfUnion) {
82+ DisjointUnionSets dsu (5 );
83+
84+ dsu.UnionSets (2 , 2 );
85+
86+ EXPECT_EQ (dsu.Find (2 ), 2 ) << " Self-union should not change the parent" ;
87+ }
88+
89+ // Test: Multiple disjoint sets
90+ TEST (DisjointUnionSetsTest, MultipleDisjointSets) {
91+ DisjointUnionSets dsu (10 );
92+
93+ dsu.UnionSets (0 , 1 );
94+ dsu.UnionSets (2 , 3 );
95+ dsu.UnionSets (4 , 5 );
96+
97+ // Check that different sets have different roots
98+ EXPECT_EQ (dsu.Find (0 ), dsu.Find (1 ));
99+ EXPECT_EQ (dsu.Find (2 ), dsu.Find (3 ));
100+ EXPECT_EQ (dsu.Find (4 ), dsu.Find (5 ));
101+
102+ EXPECT_NE (dsu.Find (0 ), dsu.Find (2 ));
103+ EXPECT_NE (dsu.Find (2 ), dsu.Find (4 ));
104+ EXPECT_NE (dsu.Find (0 ), dsu.Find (4 ));
105+ }
106+
107+ TEST (DisjointUnionSetsTest, IdempotentUnions) {
108+ DisjointUnionSets dsu (5 );
109+
110+ dsu.UnionSets (0 , 1 );
111+ const auto root1 = dsu.Find (0 );
112+
113+ dsu.UnionSets (0 , 1 );
114+ dsu.UnionSets (1 , 0 );
115+
116+ EXPECT_EQ (dsu.Find (0 ), root1)
117+ << " Repeated unions should not change the structure" ;
118+ }
119+
120+ TEST (DisjointUnionSetsTest, LargeSet) {
121+ DisjointUnionSets dsu (1000 );
122+
123+ // Union all elements into one set
124+ for (auto i = 1 ; i < 1000 ; ++i) {
125+ dsu.UnionSets (0 , i);
126+ }
127+
128+ const auto root = dsu.Find (0 );
129+ for (int i = 1 ; i < 1000 ; ++i) {
130+ EXPECT_EQ (dsu.Find (i), root) << " All elements should be in the same set" ;
131+ }
132+ }
133+
134+ TEST (DisjointUnionSetsTest, AlternatingUnions) {
135+ DisjointUnionSets dsu (8 );
136+
137+ dsu.UnionSets (0 , 2 );
138+ dsu.UnionSets (1 , 3 );
139+ dsu.UnionSets (4 , 6 );
140+ dsu.UnionSets (5 , 7 );
141+
142+ dsu.UnionSets (0 , 4 );
143+ dsu.UnionSets (1 , 5 );
144+
145+ dsu.UnionSets (0 , 1 );
146+
147+ // All should be in the same set now
148+ const auto root = dsu.Find (0 );
149+ for (int i = 1 ; i < 8 ; ++i) {
150+ EXPECT_EQ (dsu.Find (i), root);
151+ }
152+ }
0 commit comments