diff --git a/src/main/java/com/dataStructures/DisjointSet.java b/src/main/java/com/dataStructures/DisjointSet.java
new file mode 100644
index 00000000..c2a59c32
--- /dev/null
+++ b/src/main/java/com/dataStructures/DisjointSet.java
@@ -0,0 +1,136 @@
+package src.main.java.com.dataStructures;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * An implementation of disjoint-set, represented by rooted trees.
+ *
+ * Actually, the instance of {@link DisjointSet} is a disjoint-set forests.
+ *
+ *
+ * Disjoint-set operations:
+ *
+ * 1. quickly unites two sets into a new set, requiring O(1) time.
+ *
+ * 2. quickly query two elements whether contained in the same set, requiring about O(1) time.
+ *
+ * @author yangxf
+ */
+public class DisjointSet implements Serializable {
+ private static final long serialVersionUID = 3134700471905625636L;
+
+ private Map> nodeMap = new HashMap<>();
+
+ /**
+ * Add an element to the disjoint-set forests as a set.
+ */
+ public void makeSet(T element) {
+ checkNotNull(element, "element");
+ nodeMap.putIfAbsent(element, new Node<>());
+ }
+
+ /**
+ * Unites the set that contains left and the set that contains right
+ * into a new set with the union-by-rank heuristic.
+ *
+ * Rank is an upper bound on the height of node.
+ */
+ public void union(T left, T right) {
+ checkNotNull(left, "element");
+ checkNotNull(right, "element");
+
+ Node leftNode = nodeMap.get(left),
+ rightNode = nodeMap.get(right);
+
+ if (leftNode == null) {
+ throw new NoSuchElementException(left.toString());
+ }
+
+ if (rightNode == null) {
+ throw new NoSuchElementException(right.toString());
+ }
+
+ Node leftSet = findSet(leftNode),
+ rightSet = findSet(rightNode);
+
+ if (leftSet == rightSet) {
+ return;
+ }
+
+ if (leftSet.rank < rightSet.rank) {
+ leftSet.parent = rightSet;
+ } else {
+ rightSet.parent = leftSet;
+ if (leftSet.rank == rightSet.rank) {
+ leftSet.rank++;
+ }
+ }
+ }
+
+ /**
+ * Query two elements whether contained in the same set.
+ */
+ public boolean isConnected(T left, T right) {
+ if (left == null || right == null) {
+ return false;
+ }
+
+ Node leftNode = nodeMap.get(left);
+ if (leftNode == null) {
+ return false;
+ }
+
+ Node rightNode = nodeMap.get(right);
+ if (rightNode == null) {
+ return false;
+ }
+
+ if (leftNode == rightNode) {
+ return true;
+ }
+
+ return findSet(leftNode) == findSet(rightNode);
+ }
+
+ public Collection> toSets() {
+ Map, Set> setMap = new HashMap<>();
+ for (Map.Entry> entry : nodeMap.entrySet()) {
+ setMap.computeIfAbsent(findSet(entry.getValue()), k -> new HashSet<>())
+ .add(entry.getKey());
+ }
+ return setMap.values();
+ }
+
+ public void show() {
+ toSets().forEach(System.out::println);
+ }
+
+ /**
+ * Find the set that contains the node, actual is the first node of the set.
+ *
+ * Backtracking with path compression.
+ */
+ private Node findSet(Node node) {
+ if (node != node.parent) {
+ node.parent = findSet(node.parent);
+ }
+ return node.parent;
+ }
+
+ private static void checkNotNull(Object obj, String msg) {
+ if (obj == null) {
+ throw new NullPointerException(msg + " must be not null");
+ }
+ }
+
+ static class Node {
+ int rank;
+ Node parent;
+
+ Node() {
+ parent = this;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/dataStructures/DisjointSetTest.java b/src/test/java/com/dataStructures/DisjointSetTest.java
new file mode 100644
index 00000000..5f13190d
--- /dev/null
+++ b/src/test/java/com/dataStructures/DisjointSetTest.java
@@ -0,0 +1,34 @@
+package src.test.java.com.dataStructures;
+
+import org.junit.Test;
+import src.main.java.com.dataStructures.DisjointSet;
+
+import static org.junit.Assert.*;
+
+public class DisjointSetTest {
+ @Test
+ public void test() {
+ DisjointSet