Skip to content

Commit 822c91c

Browse files
authored
Merge pull request TheAlgorithms#716 from MrYangxf/Development
Add an implementation of disjoint-set
2 parents ee8147c + 01b0296 commit 822c91c

File tree

2 files changed

+170
-0
lines changed

2 files changed

+170
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package src.main.java.com.dataStructures;
2+
3+
import java.io.Serializable;
4+
import java.util.*;
5+
6+
/**
7+
* An implementation of disjoint-set, represented by rooted trees.
8+
* <p>
9+
* Actually, the instance of {@link DisjointSet} is a disjoint-set forests.
10+
*
11+
* <p>
12+
* Disjoint-set operations:
13+
* <p>
14+
* 1. quickly unites two sets into a new set, requiring O(1) time.
15+
* <p>
16+
* 2. quickly query two elements whether contained in the same set, requiring about O(1) time.
17+
*
18+
* @author yangxf
19+
*/
20+
public class DisjointSet<T> implements Serializable {
21+
private static final long serialVersionUID = 3134700471905625636L;
22+
23+
private Map<T, Node<T>> nodeMap = new HashMap<>();
24+
25+
/**
26+
* Add an element to the disjoint-set forests as a set.
27+
*/
28+
public void makeSet(T element) {
29+
checkNotNull(element, "element");
30+
nodeMap.putIfAbsent(element, new Node<>());
31+
}
32+
33+
/**
34+
* Unites the set that contains left and the set that contains right
35+
* into a new set with the union-by-rank heuristic.
36+
* <p>
37+
* Rank is an upper bound on the height of node.
38+
*/
39+
public void union(T left, T right) {
40+
checkNotNull(left, "element");
41+
checkNotNull(right, "element");
42+
43+
Node<T> leftNode = nodeMap.get(left),
44+
rightNode = nodeMap.get(right);
45+
46+
if (leftNode == null) {
47+
throw new NoSuchElementException(left.toString());
48+
}
49+
50+
if (rightNode == null) {
51+
throw new NoSuchElementException(right.toString());
52+
}
53+
54+
Node<T> leftSet = findSet(leftNode),
55+
rightSet = findSet(rightNode);
56+
57+
if (leftSet == rightSet) {
58+
return;
59+
}
60+
61+
if (leftSet.rank < rightSet.rank) {
62+
leftSet.parent = rightSet;
63+
} else {
64+
rightSet.parent = leftSet;
65+
if (leftSet.rank == rightSet.rank) {
66+
leftSet.rank++;
67+
}
68+
}
69+
}
70+
71+
/**
72+
* Query two elements whether contained in the same set.
73+
*/
74+
public boolean isConnected(T left, T right) {
75+
if (left == null || right == null) {
76+
return false;
77+
}
78+
79+
Node<T> leftNode = nodeMap.get(left);
80+
if (leftNode == null) {
81+
return false;
82+
}
83+
84+
Node<T> rightNode = nodeMap.get(right);
85+
if (rightNode == null) {
86+
return false;
87+
}
88+
89+
if (leftNode == rightNode) {
90+
return true;
91+
}
92+
93+
return findSet(leftNode) == findSet(rightNode);
94+
}
95+
96+
public Collection<Set<T>> toSets() {
97+
Map<Node<T>, Set<T>> setMap = new HashMap<>();
98+
for (Map.Entry<T, Node<T>> entry : nodeMap.entrySet()) {
99+
setMap.computeIfAbsent(findSet(entry.getValue()), k -> new HashSet<>())
100+
.add(entry.getKey());
101+
}
102+
return setMap.values();
103+
}
104+
105+
public void show() {
106+
toSets().forEach(System.out::println);
107+
}
108+
109+
/**
110+
* Find the set that contains the node, actual is the first node of the set.
111+
* <p>
112+
* Backtracking with path compression.
113+
*/
114+
private Node<T> findSet(Node<T> node) {
115+
if (node != node.parent) {
116+
node.parent = findSet(node.parent);
117+
}
118+
return node.parent;
119+
}
120+
121+
private static void checkNotNull(Object obj, String msg) {
122+
if (obj == null) {
123+
throw new NullPointerException(msg + " must be not null");
124+
}
125+
}
126+
127+
static class Node<T> {
128+
int rank;
129+
Node<T> parent;
130+
131+
Node() {
132+
parent = this;
133+
}
134+
}
135+
136+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package src.test.java.com.dataStructures;
2+
3+
import org.junit.Test;
4+
import src.main.java.com.dataStructures.DisjointSet;
5+
6+
import static org.junit.Assert.*;
7+
8+
public class DisjointSetTest {
9+
@Test
10+
public void test() {
11+
DisjointSet<Object> set = new DisjointSet<>();
12+
13+
set.makeSet("flink");
14+
set.makeSet("c++");
15+
set.makeSet("java");
16+
set.makeSet("py");
17+
set.makeSet("spark");
18+
19+
set.union("java", "c++");
20+
21+
assertTrue(set.isConnected("java", "c++"));
22+
assertFalse(set.isConnected("java", "py"));
23+
24+
set.union("c++", "py");
25+
assertTrue(set.isConnected("java", "py"));
26+
27+
set.makeSet("lisp");
28+
set.union("lisp", "py");
29+
30+
assertTrue(set.isConnected("c++", "lisp"));
31+
32+
set.show();
33+
}
34+
}

0 commit comments

Comments
 (0)