From 94621fb63eafcf18666dfad176fffc28f82b439a Mon Sep 17 00:00:00 2001 From: Manan Solanki <76104205+Manan-09@users.noreply.github.com> Date: Sun, 10 Sep 2023 22:30:35 +0530 Subject: [PATCH] Enhancing DisjointSetUnion data structure (#4366) * Enhancing DisjointSetUnion data structure * Linter resolved * Linter resolved * Linter resolved * Linter resolved * Added next line * added next Line * Resolve review comments --------- Co-authored-by: Bama Charan Chhandogi --- .../disjointsets/DisjointSets.java | 33 ------------ .../datastructures/disjointsets/Node.java | 13 ----- .../disjointsetunion/DisjointSetUnion.java | 53 +++++++++++++++++++ .../datastructures/disjointsetunion/Node.java | 25 +++++++++ .../DisjointSetUnionTest.java | 51 ++++++++++++++++++ 5 files changed, 129 insertions(+), 46 deletions(-) delete mode 100644 src/main/java/com/thealgorithms/datastructures/disjointsets/DisjointSets.java delete mode 100644 src/main/java/com/thealgorithms/datastructures/disjointsets/Node.java create mode 100644 src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java create mode 100644 src/main/java/com/thealgorithms/datastructures/disjointsetunion/Node.java create mode 100644 src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java diff --git a/src/main/java/com/thealgorithms/datastructures/disjointsets/DisjointSets.java b/src/main/java/com/thealgorithms/datastructures/disjointsets/DisjointSets.java deleted file mode 100644 index cf26fce78088..000000000000 --- a/src/main/java/com/thealgorithms/datastructures/disjointsets/DisjointSets.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.thealgorithms.datastructures.disjointsets; - -public class DisjointSets { - - public Node MakeSet(T x) { - return new Node(x); - } - - public Node FindSet(Node node) { - if (node != node.parent) { - node.parent = FindSet(node.parent); - } - - return node.parent; - } - - public void UnionSet(Node x, Node y) { - Node nx = FindSet(x); - Node ny = FindSet(y); - - if (nx == ny) { - return; - } - if (nx.rank > ny.rank) { - ny.parent = nx; - } else if (ny.rank > nx.rank) { - nx.parent = ny; - } else { - nx.parent = ny; - ny.rank++; - } - } -} diff --git a/src/main/java/com/thealgorithms/datastructures/disjointsets/Node.java b/src/main/java/com/thealgorithms/datastructures/disjointsets/Node.java deleted file mode 100644 index f2054331dc14..000000000000 --- a/src/main/java/com/thealgorithms/datastructures/disjointsets/Node.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.thealgorithms.datastructures.disjointsets; - -public class Node { - - public int rank; - public Node parent; - public T data; - - public Node(T data) { - this.data = data; - parent = this; - } -} diff --git a/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java b/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java new file mode 100644 index 000000000000..583800998c81 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java @@ -0,0 +1,53 @@ +package com.thealgorithms.datastructures.disjointsetunion; + +/** + * Disjoint Set Union or DSU is useful for solving problems related to connected components, + * cycle detection in graphs, and maintaining relationships in disjoint sets of data. + * It is commonly employed in graph algorithms and problems. + * + * @see Disjoint Set Union + */ +public class DisjointSetUnion { + + /** + * Creates a new node of DSU with parent initialised as same node + */ + public Node makeSet(final T x) { + return new Node(x); + } + + /** + * Finds and returns the representative (root) element of the set to which a given element belongs. + * This operation uses path compression to optimize future findSet operations. + */ + public Node findSet(Node node) { + while (node != node.parent) { + node = node.parent; + } + return node; + } + + /** + * Unions two sets by merging their representative elements. The merge is performed based on the rank of each set + * to ensure efficient merging and path compression to optimize future findSet operations. + */ + public void unionSets(final Node x, final Node y) { + Node nx = findSet(x); + Node ny = findSet(y); + + if (nx == ny) { + return; // Both elements already belong to the same set. + } + // Merging happens based on rank of node, this is done to avoid long chaining of nodes and reduce time + // to find root of the component. Idea is to attach small components in big, instead of other way around. + if (nx.rank > ny.rank) { + ny.parent = nx; + } else if (ny.rank > nx.rank) { + nx.parent = ny; + } else { + // Both sets have the same rank; choose one as the parent and increment the rank. + ny.parent = nx; + nx.rank++; + } + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/disjointsetunion/Node.java b/src/main/java/com/thealgorithms/datastructures/disjointsetunion/Node.java new file mode 100644 index 000000000000..260f297bd713 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/disjointsetunion/Node.java @@ -0,0 +1,25 @@ +package com.thealgorithms.datastructures.disjointsetunion; + +public class Node { + + /** + * The rank of the node, used for optimizing union operations. + */ + public int rank; + + /** + * Reference to the parent node in the set. + * Initially, a node is its own parent (represents a singleton set). + */ + public Node parent; + + /** + * The data element associated with the node. + */ + public T data; + + public Node(final T data) { + this.data = data; + parent = this; // Initially, a node is its own parent. + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java b/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java new file mode 100644 index 000000000000..a10a99d40496 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java @@ -0,0 +1,51 @@ +package com.thealgorithms.datastructures.disjointsetunion; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class DisjointSetUnionTest { + + @Test + public void testMakeSet() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node node = dsu.makeSet(1); + assertNotNull(node); + Assertions.assertEquals(node, node.parent); + } + + @Test + public void testUnionFindSet() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node node1 = dsu.makeSet(1); + Node node2 = dsu.makeSet(2); + Node node3 = dsu.makeSet(3); + Node node4 = dsu.makeSet(4); + + dsu.unionSets(node1, node2); + dsu.unionSets(node3, node2); + dsu.unionSets(node3, node4); + dsu.unionSets(node1, node3); + + Node root1 = dsu.findSet(node1); + Node root2 = dsu.findSet(node2); + Node root3 = dsu.findSet(node3); + Node root4 = dsu.findSet(node4); + + Assertions.assertEquals(node1, node1.parent); + Assertions.assertEquals(node1, node2.parent); + Assertions.assertEquals(node1, node3.parent); + Assertions.assertEquals(node1, node4.parent); + + Assertions.assertEquals(node1, root1); + Assertions.assertEquals(node1, root2); + Assertions.assertEquals(node1, root3); + Assertions.assertEquals(node1, root4); + + Assertions.assertEquals(1, node1.rank); + Assertions.assertEquals(0, node2.rank); + Assertions.assertEquals(0, node3.rank); + Assertions.assertEquals(0, node4.rank); + } +}