From 9839130ecdf7c88911692d0b77171047f7635dd3 Mon Sep 17 00:00:00 2001 From: anandraj095 Date: Wed, 17 Dec 2025 12:06:43 +0530 Subject: [PATCH 1/5] Add Kruskal's Minimum Spanning Tree algorithm using Union-Find --- .../java/com/thealgorithms/graph/Edge.java | 35 ++++++++ .../com/thealgorithms/graph/KruskalMST.java | 90 +++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/main/java/com/thealgorithms/graph/Edge.java create mode 100644 src/main/java/com/thealgorithms/graph/KruskalMST.java diff --git a/src/main/java/com/thealgorithms/graph/Edge.java b/src/main/java/com/thealgorithms/graph/Edge.java new file mode 100644 index 000000000000..279a6662b7cc --- /dev/null +++ b/src/main/java/com/thealgorithms/graph/Edge.java @@ -0,0 +1,35 @@ +package com.thealgorithms.graph; + +/** + * Represents an edge in an undirected weighted graph. + */ +public class Edge implements Comparable { + + public final int source; + public final int destination; + public final int weight; + + /** + * Constructs an edge with given source, destination, and weight. + * + * @param source the source vertex + * @param destination the destination vertex + * @param weight the weight of the edge + */ + public Edge(final int source, final int destination, final int weight) { + this.source = source; + this.destination = destination; + this.weight = weight; + } + + /** + * Compares edges based on their weight. + * + * @param other the edge to compare with + * @return comparison result + */ + @Override + public int compareTo(final Edge other) { + return Integer.compare(this.weight, other.weight); + } +} diff --git a/src/main/java/com/thealgorithms/graph/KruskalMST.java b/src/main/java/com/thealgorithms/graph/KruskalMST.java new file mode 100644 index 000000000000..983737119aa2 --- /dev/null +++ b/src/main/java/com/thealgorithms/graph/KruskalMST.java @@ -0,0 +1,90 @@ +package com.thealgorithms.graph; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Implementation of Kruskal's Algorithm to find + * the Minimum Spanning Tree (MST) of a connected, + * undirected, weighted graph. + */ +public final class KruskalMST { + + private KruskalMST() { + // Utility class + } + + /** + * Finds the Minimum Spanning Tree using Kruskal's Algorithm. + * + * @param vertices number of vertices in the graph + * @param edges list of all edges in the graph + * @return list of edges forming the MST + * @throws IllegalArgumentException if vertices <= 0 + */ + public static List findMST(final int vertices, final List edges) { + if (vertices <= 0) { + throw new IllegalArgumentException("Number of vertices must be positive"); + } + + final List mst = new ArrayList<>(); + final DisjointSetUnion dsu = new DisjointSetUnion(vertices); + + Collections.sort(edges); + + for (final Edge edge : edges) { + final int rootU = dsu.find(edge.source); + final int rootV = dsu.find(edge.destination); + + if (rootU != rootV) { + mst.add(edge); + dsu.union(rootU, rootV); + + if (mst.size() == vertices - 1) { + break; + } + } + } + + return mst; + } + + /** + * Disjoint Set Union (Union-Find) with + * path compression and union by rank. + */ + private static final class DisjointSetUnion { + + private final int[] parent; + private final int[] rank; + + private DisjointSetUnion(final int size) { + parent = new int[size]; + rank = new int[size]; + + for (int i = 0; i < size; i++) { + parent[i] = i; + rank[i] = 0; + } + } + + private int find(final int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + private void union(final int u, final int v) { + if (rank[u] < rank[v]) { + parent[u] = v; + } else if (rank[u] > rank[v]) { + parent[v] = u; + } else { + parent[v] = u; + rank[u]++; + } + } + } +} From 5b721b217e884c544234d7ce306017447b650e98 Mon Sep 17 00:00:00 2001 From: anandraj095 Date: Wed, 17 Dec 2025 12:41:40 +0530 Subject: [PATCH 2/5] Add Kruskal's Minimum Spanning Tree algorithm Test --- .../thealgorithms/graph/KruskalMSTTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/test/java/com/thealgorithms/graph/KruskalMSTTest.java diff --git a/src/test/java/com/thealgorithms/graph/KruskalMSTTest.java b/src/test/java/com/thealgorithms/graph/KruskalMSTTest.java new file mode 100644 index 000000000000..b09099f5fdf1 --- /dev/null +++ b/src/test/java/com/thealgorithms/graph/KruskalMSTTest.java @@ -0,0 +1,50 @@ +package com.thealgorithms.graph; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; + +/** + * Test cases for Kruskal's Minimum Spanning Tree algorithm. + */ +class KruskalMSTTest { + + @Test + void testFindMSTWithSimpleGraph() { + final int vertices = 4; + + final List edges = new ArrayList<>(); + edges.add(new Edge(0, 1, 10)); + edges.add(new Edge(0, 2, 6)); + edges.add(new Edge(0, 3, 5)); + edges.add(new Edge(1, 3, 15)); + edges.add(new Edge(2, 3, 4)); + + final List mst = KruskalMST.findMST(vertices, edges); + + assertNotNull(mst, "MST should not be null"); + assertEquals(vertices - 1, mst.size(), "MST should contain V-1 edges"); + + int totalWeight = 0; + for (final Edge edge : mst) { + totalWeight += edge.weight; + } + + assertEquals(19, totalWeight, "Total weight of MST is incorrect"); + } + + @Test + void testFindMSTWithSingleVertex() { + final int vertices = 1; + final List edges = new ArrayList<>(); + + final List mst = KruskalMST.findMST(vertices, edges); + + assertNotNull(mst, "MST should not be null"); + assertEquals(0, mst.size(), "MST of single vertex graph should be empty"); + } +} From 54b8922f51fb439376212d8d02136cd15c8de285 Mon Sep 17 00:00:00 2001 From: anandraj095 Date: Wed, 17 Dec 2025 13:01:37 +0530 Subject: [PATCH 3/5] Improve robustness and test coverage for Kruskal MST --- .../com/thealgorithms/graph/KruskalMST.java | 11 ++++++-- .../thealgorithms/graph/KruskalMSTTest.java | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/thealgorithms/graph/KruskalMST.java b/src/main/java/com/thealgorithms/graph/KruskalMST.java index 983737119aa2..211acba79185 100644 --- a/src/main/java/com/thealgorithms/graph/KruskalMST.java +++ b/src/main/java/com/thealgorithms/graph/KruskalMST.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; /** * Implementation of Kruskal's Algorithm to find @@ -22,18 +23,22 @@ private KruskalMST() { * @param edges list of all edges in the graph * @return list of edges forming the MST * @throws IllegalArgumentException if vertices <= 0 + * @throws NullPointerException if edges is null */ public static List findMST(final int vertices, final List edges) { if (vertices <= 0) { throw new IllegalArgumentException("Number of vertices must be positive"); } + Objects.requireNonNull(edges, "Edges list must not be null"); + + final List sortedEdges = new ArrayList<>(edges); + Collections.sort(sortedEdges); + final List mst = new ArrayList<>(); final DisjointSetUnion dsu = new DisjointSetUnion(vertices); - Collections.sort(edges); - - for (final Edge edge : edges) { + for (final Edge edge : sortedEdges) { final int rootU = dsu.find(edge.source); final int rootV = dsu.find(edge.destination); diff --git a/src/test/java/com/thealgorithms/graph/KruskalMSTTest.java b/src/test/java/com/thealgorithms/graph/KruskalMSTTest.java index b09099f5fdf1..9b2506affc29 100644 --- a/src/test/java/com/thealgorithms/graph/KruskalMSTTest.java +++ b/src/test/java/com/thealgorithms/graph/KruskalMSTTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.ArrayList; import java.util.List; @@ -47,4 +48,31 @@ void testFindMSTWithSingleVertex() { assertNotNull(mst, "MST should not be null"); assertEquals(0, mst.size(), "MST of single vertex graph should be empty"); } + + @Test + void testInvalidVertexCountThrowsException() { + final List edges = new ArrayList<>(); + + assertThrows( + IllegalArgumentException.class, + () -> KruskalMST.findMST(0, edges), + "Expected exception for non-positive vertex count" + ); + } + + @Test + void testPathCompressionScenario() { + final int vertices = 5; + + final List edges = new ArrayList<>(); + edges.add(new Edge(0, 1, 1)); + edges.add(new Edge(1, 2, 2)); + edges.add(new Edge(2, 3, 3)); + edges.add(new Edge(3, 4, 4)); + + final List mst = KruskalMST.findMST(vertices, edges); + + assertNotNull(mst); + assertEquals(vertices - 1, mst.size(), "MST should contain V-1 edges"); + } } From 3a5ee8d78dbf9a3d1d0c9b2ddb6ac2806274eb0d Mon Sep 17 00:00:00 2001 From: anandraj095 Date: Fri, 19 Dec 2025 16:04:33 +0530 Subject: [PATCH 4/5] Apply google-java-format to Kruskal MST implementation --- .../java/com/thealgorithms/graph/Edge.java | 54 ++++---- .../com/thealgorithms/graph/KruskalMST.java | 128 +++++++++--------- .../thealgorithms/graph/KruskalMSTTest.java | 98 +++++++------- 3 files changed, 135 insertions(+), 145 deletions(-) diff --git a/src/main/java/com/thealgorithms/graph/Edge.java b/src/main/java/com/thealgorithms/graph/Edge.java index 279a6662b7cc..255a2af87073 100644 --- a/src/main/java/com/thealgorithms/graph/Edge.java +++ b/src/main/java/com/thealgorithms/graph/Edge.java @@ -1,35 +1,33 @@ package com.thealgorithms.graph; -/** - * Represents an edge in an undirected weighted graph. - */ +/** Represents an edge in an undirected weighted graph. */ public class Edge implements Comparable { - public final int source; - public final int destination; - public final int weight; + public final int source; + public final int destination; + public final int weight; - /** - * Constructs an edge with given source, destination, and weight. - * - * @param source the source vertex - * @param destination the destination vertex - * @param weight the weight of the edge - */ - public Edge(final int source, final int destination, final int weight) { - this.source = source; - this.destination = destination; - this.weight = weight; - } + /** + * Constructs an edge with given source, destination, and weight. + * + * @param source the source vertex + * @param destination the destination vertex + * @param weight the weight of the edge + */ + public Edge(final int source, final int destination, final int weight) { + this.source = source; + this.destination = destination; + this.weight = weight; + } - /** - * Compares edges based on their weight. - * - * @param other the edge to compare with - * @return comparison result - */ - @Override - public int compareTo(final Edge other) { - return Integer.compare(this.weight, other.weight); - } + /** + * Compares edges based on their weight. + * + * @param other the edge to compare with + * @return comparison result + */ + @Override + public int compareTo(final Edge other) { + return Integer.compare(this.weight, other.weight); + } } diff --git a/src/main/java/com/thealgorithms/graph/KruskalMST.java b/src/main/java/com/thealgorithms/graph/KruskalMST.java index 211acba79185..db48cc973436 100644 --- a/src/main/java/com/thealgorithms/graph/KruskalMST.java +++ b/src/main/java/com/thealgorithms/graph/KruskalMST.java @@ -6,90 +6,86 @@ import java.util.Objects; /** - * Implementation of Kruskal's Algorithm to find - * the Minimum Spanning Tree (MST) of a connected, + * Implementation of Kruskal's Algorithm to find the Minimum Spanning Tree (MST) of a connected, * undirected, weighted graph. */ public final class KruskalMST { - private KruskalMST() { - // Utility class + private KruskalMST() { + // Utility class + } + + /** + * Finds the Minimum Spanning Tree using Kruskal's Algorithm. + * + * @param vertices number of vertices in the graph + * @param edges list of all edges in the graph + * @return list of edges forming the MST + * @throws IllegalArgumentException if vertices <= 0 + * @throws NullPointerException if edges is null + */ + public static List findMST(final int vertices, final List edges) { + if (vertices <= 0) { + throw new IllegalArgumentException("Number of vertices must be positive"); } - /** - * Finds the Minimum Spanning Tree using Kruskal's Algorithm. - * - * @param vertices number of vertices in the graph - * @param edges list of all edges in the graph - * @return list of edges forming the MST - * @throws IllegalArgumentException if vertices <= 0 - * @throws NullPointerException if edges is null - */ - public static List findMST(final int vertices, final List edges) { - if (vertices <= 0) { - throw new IllegalArgumentException("Number of vertices must be positive"); - } - - Objects.requireNonNull(edges, "Edges list must not be null"); + Objects.requireNonNull(edges, "Edges list must not be null"); - final List sortedEdges = new ArrayList<>(edges); - Collections.sort(sortedEdges); + final List sortedEdges = new ArrayList<>(edges); + Collections.sort(sortedEdges); - final List mst = new ArrayList<>(); - final DisjointSetUnion dsu = new DisjointSetUnion(vertices); + final List mst = new ArrayList<>(); + final DisjointSetUnion dsu = new DisjointSetUnion(vertices); - for (final Edge edge : sortedEdges) { - final int rootU = dsu.find(edge.source); - final int rootV = dsu.find(edge.destination); + for (final Edge edge : sortedEdges) { + final int rootU = dsu.find(edge.source); + final int rootV = dsu.find(edge.destination); - if (rootU != rootV) { - mst.add(edge); - dsu.union(rootU, rootV); + if (rootU != rootV) { + mst.add(edge); + dsu.union(rootU, rootV); - if (mst.size() == vertices - 1) { - break; - } - } + if (mst.size() == vertices - 1) { + break; } - - return mst; + } } - /** - * Disjoint Set Union (Union-Find) with - * path compression and union by rank. - */ - private static final class DisjointSetUnion { + return mst; + } - private final int[] parent; - private final int[] rank; + /** Disjoint Set Union (Union-Find) with path compression and union by rank. */ + private static final class DisjointSetUnion { - private DisjointSetUnion(final int size) { - parent = new int[size]; - rank = new int[size]; + private final int[] parent; + private final int[] rank; - for (int i = 0; i < size; i++) { - parent[i] = i; - rank[i] = 0; - } - } + private DisjointSetUnion(final int size) { + parent = new int[size]; + rank = new int[size]; - private int find(final int node) { - if (parent[node] != node) { - parent[node] = find(parent[node]); - } - return parent[node]; - } + for (int i = 0; i < size; i++) { + parent[i] = i; + rank[i] = 0; + } + } - private void union(final int u, final int v) { - if (rank[u] < rank[v]) { - parent[u] = v; - } else if (rank[u] > rank[v]) { - parent[v] = u; - } else { - parent[v] = u; - rank[u]++; - } - } + private int find(final int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + private void union(final int u, final int v) { + if (rank[u] < rank[v]) { + parent[u] = v; + } else if (rank[u] > rank[v]) { + parent[v] = u; + } else { + parent[v] = u; + rank[u]++; + } } + } } diff --git a/src/test/java/com/thealgorithms/graph/KruskalMSTTest.java b/src/test/java/com/thealgorithms/graph/KruskalMSTTest.java index 9b2506affc29..003d6887b4ad 100644 --- a/src/test/java/com/thealgorithms/graph/KruskalMSTTest.java +++ b/src/test/java/com/thealgorithms/graph/KruskalMSTTest.java @@ -6,73 +6,69 @@ import java.util.ArrayList; import java.util.List; - import org.junit.jupiter.api.Test; -/** - * Test cases for Kruskal's Minimum Spanning Tree algorithm. - */ +/** Test cases for Kruskal's Minimum Spanning Tree algorithm. */ class KruskalMSTTest { - @Test - void testFindMSTWithSimpleGraph() { - final int vertices = 4; - - final List edges = new ArrayList<>(); - edges.add(new Edge(0, 1, 10)); - edges.add(new Edge(0, 2, 6)); - edges.add(new Edge(0, 3, 5)); - edges.add(new Edge(1, 3, 15)); - edges.add(new Edge(2, 3, 4)); + @Test + void testFindMSTWithSimpleGraph() { + final int vertices = 4; - final List mst = KruskalMST.findMST(vertices, edges); + final List edges = new ArrayList<>(); + edges.add(new Edge(0, 1, 10)); + edges.add(new Edge(0, 2, 6)); + edges.add(new Edge(0, 3, 5)); + edges.add(new Edge(1, 3, 15)); + edges.add(new Edge(2, 3, 4)); - assertNotNull(mst, "MST should not be null"); - assertEquals(vertices - 1, mst.size(), "MST should contain V-1 edges"); + final List mst = KruskalMST.findMST(vertices, edges); - int totalWeight = 0; - for (final Edge edge : mst) { - totalWeight += edge.weight; - } + assertNotNull(mst, "MST should not be null"); + assertEquals(vertices - 1, mst.size(), "MST should contain V-1 edges"); - assertEquals(19, totalWeight, "Total weight of MST is incorrect"); + int totalWeight = 0; + for (final Edge edge : mst) { + totalWeight += edge.weight; } - @Test - void testFindMSTWithSingleVertex() { - final int vertices = 1; - final List edges = new ArrayList<>(); + assertEquals(19, totalWeight, "Total weight of MST is incorrect"); + } - final List mst = KruskalMST.findMST(vertices, edges); + @Test + void testFindMSTWithSingleVertex() { + final int vertices = 1; + final List edges = new ArrayList<>(); - assertNotNull(mst, "MST should not be null"); - assertEquals(0, mst.size(), "MST of single vertex graph should be empty"); - } + final List mst = KruskalMST.findMST(vertices, edges); - @Test - void testInvalidVertexCountThrowsException() { - final List edges = new ArrayList<>(); + assertNotNull(mst, "MST should not be null"); + assertEquals(0, mst.size(), "MST of single vertex graph should be empty"); + } - assertThrows( - IllegalArgumentException.class, - () -> KruskalMST.findMST(0, edges), - "Expected exception for non-positive vertex count" - ); - } + @Test + void testInvalidVertexCountThrowsException() { + final List edges = new ArrayList<>(); - @Test - void testPathCompressionScenario() { - final int vertices = 5; + assertThrows( + IllegalArgumentException.class, + () -> KruskalMST.findMST(0, edges), + "Expected exception for non-positive vertex count"); + } - final List edges = new ArrayList<>(); - edges.add(new Edge(0, 1, 1)); - edges.add(new Edge(1, 2, 2)); - edges.add(new Edge(2, 3, 3)); - edges.add(new Edge(3, 4, 4)); + @Test + void testPathCompressionScenario() { + final int vertices = 5; - final List mst = KruskalMST.findMST(vertices, edges); + final List edges = new ArrayList<>(); + edges.add(new Edge(0, 1, 1)); + edges.add(new Edge(1, 2, 2)); + edges.add(new Edge(2, 3, 3)); + edges.add(new Edge(3, 4, 4)); - assertNotNull(mst); - assertEquals(vertices - 1, mst.size(), "MST should contain V-1 edges"); - } + final List mst = KruskalMST.findMST(vertices, edges); + + assertNotNull(mst); + assertEquals(vertices - 1, mst.size(), "MST should contain V-1 edges"); + } } From aa5a1e55748c93df020e53eab599b060ee975753 Mon Sep 17 00:00:00 2001 From: anandraj095 Date: Fri, 19 Dec 2025 16:13:06 +0530 Subject: [PATCH 5/5] Fix Kruskal MST method structure and formatting --- src/main/java/com/thealgorithms/graph/KruskalMST.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/graph/KruskalMST.java b/src/main/java/com/thealgorithms/graph/KruskalMST.java index db48cc973436..a1badf233afb 100644 --- a/src/main/java/com/thealgorithms/graph/KruskalMST.java +++ b/src/main/java/com/thealgorithms/graph/KruskalMST.java @@ -50,7 +50,6 @@ public static List findMST(final int vertices, final List edges) { } } } - return mst; }