Skip to content

Commit 401d873

Browse files
authored
Add tests, remove main in UnionFind (#5678)
1 parent fb11d45 commit 401d873

File tree

3 files changed

+126
-27
lines changed

3 files changed

+126
-27
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,7 @@
10191019
* [SortOrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java)
10201020
* [SquareRootBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java)
10211021
* [TestSearchInARowAndColWiseSortedMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java)
1022+
* [UnionFindTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/UnionFindTest.java)
10221023
* sorts
10231024
* [BeadSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BeadSortTest.java)
10241025
* [BinaryInsertionSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BinaryInsertionSortTest.java)

src/main/java/com/thealgorithms/searches/UnionFind.java

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,28 @@
44
import java.util.Arrays;
55
import java.util.List;
66

7+
/**
8+
* The Union-Find data structure, also known as Disjoint Set Union (DSU),
9+
* is a data structure that tracks a set of elements partitioned into
10+
* disjoint (non-overlapping) subsets. It supports two main operations:
11+
*
12+
* 1. **Find**: Determine which subset a particular element is in.
13+
* 2. **Union**: Join two subsets into a single subset.
14+
*
15+
* This implementation uses path compression in the `find` operation
16+
* and union by rank in the `union` operation for efficiency.
17+
*/
718
public class UnionFind {
819

9-
private final int[] p;
10-
private final int[] r;
20+
private final int[] p; // Parent array
21+
private final int[] r; // Rank array
1122

23+
/**
24+
* Initializes a Union-Find data structure with n elements.
25+
* Each element is its own parent initially.
26+
*
27+
* @param n the number of elements
28+
*/
1229
public UnionFind(int n) {
1330
p = new int[n];
1431
r = new int[n];
@@ -18,19 +35,33 @@ public UnionFind(int n) {
1835
}
1936
}
2037

38+
/**
39+
* Finds the root of the set containing the element i.
40+
* Uses path compression to flatten the structure.
41+
*
42+
* @param i the element to find
43+
* @return the root of the set
44+
*/
2145
public int find(int i) {
2246
int parent = p[i];
2347

2448
if (i == parent) {
2549
return i;
2650
}
2751

52+
// Path compression
2853
final int result = find(parent);
2954
p[i] = result;
30-
3155
return result;
3256
}
3357

58+
/**
59+
* Unites the sets containing elements x and y.
60+
* Uses union by rank to attach the smaller tree under the larger tree.
61+
*
62+
* @param x the first element
63+
* @param y the second element
64+
*/
3465
public void union(int x, int y) {
3566
int r0 = find(x);
3667
int r1 = find(y);
@@ -39,6 +70,7 @@ public void union(int x, int y) {
3970
return;
4071
}
4172

73+
// Union by rank
4274
if (r[r0] > r[r1]) {
4375
p[r1] = r0;
4476
} else if (r[r1] > r[r0]) {
@@ -49,39 +81,24 @@ public void union(int x, int y) {
4981
}
5082
}
5183

84+
/**
85+
* Counts the number of disjoint sets.
86+
*
87+
* @return the number of disjoint sets
88+
*/
5289
public int count() {
5390
List<Integer> parents = new ArrayList<>();
5491
for (int i = 0; i < p.length; i++) {
55-
if (!parents.contains(find(i))) {
56-
parents.add(find(i));
92+
int root = find(i);
93+
if (!parents.contains(root)) {
94+
parents.add(root);
5795
}
5896
}
5997
return parents.size();
6098
}
6199

100+
@Override
62101
public String toString() {
63102
return "p " + Arrays.toString(p) + " r " + Arrays.toString(r) + "\n";
64103
}
65-
66-
// Tests
67-
public static void main(String[] args) {
68-
UnionFind uf = new UnionFind(5);
69-
System.out.println("init /w 5 (should print 'p [0, 1, 2, 3, 4] r [0, 0, 0, 0, 0]'):");
70-
System.out.println(uf);
71-
72-
uf.union(1, 2);
73-
System.out.println("union 1 2 (should print 'p [0, 1, 1, 3, 4] r [0, 1, 0, 0, 0]'):");
74-
System.out.println(uf);
75-
76-
uf.union(3, 4);
77-
System.out.println("union 3 4 (should print 'p [0, 1, 1, 3, 3] r [0, 1, 0, 1, 0]'):");
78-
System.out.println(uf);
79-
80-
uf.find(4);
81-
System.out.println("find 4 (should print 'p [0, 1, 1, 3, 3] r [0, 1, 0, 1, 0]'):");
82-
System.out.println(uf);
83-
84-
System.out.println("count (should print '3'):");
85-
System.out.println(uf.count());
86-
}
87104
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.thealgorithms.searches;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import org.junit.jupiter.api.BeforeEach;
6+
import org.junit.jupiter.api.Test;
7+
8+
class UnionFindTest {
9+
private UnionFind uf;
10+
11+
@BeforeEach
12+
void setUp() {
13+
uf = new UnionFind(10); // Initialize with 10 elements
14+
}
15+
16+
@Test
17+
void testInitialState() {
18+
// Verify that each element is its own parent and rank is 0
19+
assertEquals("p [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] r [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n", uf.toString());
20+
assertEquals(10, uf.count(), "Initial count of disjoint sets should be 10.");
21+
}
22+
23+
@Test
24+
void testUnionOperation() {
25+
uf.union(0, 1);
26+
uf.union(1, 2);
27+
assertEquals(8, uf.count(), "Count should decrease after unions.");
28+
assertEquals(0, uf.find(2), "Element 2 should point to root 0 after unions.");
29+
}
30+
31+
@Test
32+
void testUnionWithRank() {
33+
uf.union(0, 1);
34+
uf.union(1, 2); // Make 0 the root of 2
35+
uf.union(3, 4);
36+
uf.union(4, 5); // Make 3 the root of 5
37+
uf.union(0, 3); // Union two trees
38+
39+
assertEquals(5, uf.count(), "Count should decrease after unions.");
40+
assertEquals(0, uf.find(5), "Element 5 should point to root 0 after unions.");
41+
}
42+
43+
@Test
44+
void testFindOperation() {
45+
uf.union(2, 3);
46+
uf.union(4, 5);
47+
uf.union(3, 5); // Connect 2-3 and 4-5
48+
49+
assertEquals(2, uf.find(3), "Find operation should return the root of the set.");
50+
assertEquals(2, uf.find(5), "Find operation should return the root of the set.");
51+
}
52+
53+
@Test
54+
void testCountAfterMultipleUnions() {
55+
uf.union(0, 1);
56+
uf.union(2, 3);
57+
uf.union(4, 5);
58+
uf.union(1, 3); // Connect 0-1-2-3
59+
uf.union(5, 6);
60+
61+
assertEquals(5, uf.count(), "Count should reflect the number of disjoint sets after multiple unions.");
62+
}
63+
64+
@Test
65+
void testNoUnion() {
66+
assertEquals(10, uf.count(), "Count should remain 10 if no unions are made.");
67+
}
68+
69+
@Test
70+
void testUnionSameSet() {
71+
uf.union(1, 2);
72+
uf.union(1, 2); // Union same elements again
73+
74+
assertEquals(9, uf.count(), "Count should not decrease if union is called on the same set.");
75+
}
76+
77+
@Test
78+
void testFindOnSingleElement() {
79+
assertEquals(7, uf.find(7), "Find on a single element should return itself.");
80+
}
81+
}

0 commit comments

Comments
 (0)