diff --git a/src/main/java/com/thealgorithms/randomized/KargerMinCut.java b/src/main/java/com/thealgorithms/randomized/KargerMinCut.java
new file mode 100644
index 000000000..14f1f9745
--- /dev/null
+++ b/src/main/java/com/thealgorithms/randomized/KargerMinCut.java
@@ -0,0 +1,195 @@
+package com.thealgorithms.randomized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+/**
+ * Implementation of Karger's Minimum Cut algorithm.
+ *
+ *
Karger's algorithm is a randomized algorithm to compute the minimum cut of a connected graph.
+ * A minimum cut is the smallest set of edges that, if removed, would split the graph into two
+ * disconnected components.
+ *
+ *
The algorithm works by repeatedly contracting random edges in the graph until only two
+ * nodes remain. The edges between these two nodes represent a cut. By running the algorithm
+ * multiple times and keeping track of the smallest cut found, the probability of finding the
+ * true minimum cut increases.
+ *
+ *
Key steps of the algorithm:
+ *
+ * - Randomly select an edge and contract it, merging the two nodes into one.
+ * - Repeat the contraction process until only two nodes remain.
+ * - Count the edges between the two remaining nodes to determine the cut size.
+ * - Repeat the process multiple times to improve the likelihood of finding the true minimum cut.
+ *
+ *
+ * See more: Karger's algorithm
+ *
+ * @author MuhammadEzzatHBK
+ */
+public final class KargerMinCut {
+
+ /**
+ * Output of the Karger algorithm.
+ *
+ * @param first The first set of nodes in the cut.
+ * @param second The second set of nodes in the cut.
+ * @param minCut The size of the minimum cut.
+ */
+ public record KargerOutput(Set first, Set second, int minCut) {
+ }
+
+ private KargerMinCut() {
+ }
+
+ public static KargerOutput findMinCut(Collection nodeSet, List edges) {
+ return findMinCut(nodeSet, edges, 100);
+ }
+
+ /**
+ * Finds the minimum cut of a graph using Karger's algorithm.
+ *
+ * @param nodeSet: Input graph nodes
+ * @param edges: Input graph edges
+ * @param iterations: Iterations to run the algorithms for, more iterations = more accuracy
+ * @return A KargerOutput object containing the two sets of nodes and the size of the minimum cut.
+ */
+ public static KargerOutput findMinCut(Collection nodeSet, List edges, int iterations) {
+ Graph graph = new Graph(nodeSet, edges);
+ KargerOutput minCut = new KargerOutput(new HashSet<>(), new HashSet<>(), Integer.MAX_VALUE);
+ KargerOutput output;
+
+ // Run the algorithm multiple times to increase the probability of finding
+ for (int i = 0; i < iterations; i++) {
+ Graph clone = graph.copy();
+ output = clone.findMinCut();
+ if (output.minCut < minCut.minCut) {
+ minCut = output;
+ }
+ }
+ return minCut;
+ }
+
+ private static class DisjointSetUnion {
+ private final int[] parent;
+ int setCount;
+
+ DisjointSetUnion(int size) {
+ parent = new int[size];
+ for (int i = 0; i < size; i++) {
+ parent[i] = i;
+ }
+ setCount = size;
+ }
+
+ int find(int i) {
+ // If it's not its own parent, then it's not the root of its set
+ if (parent[i] != i) {
+ // Recursively find the root of its parent
+ // and update i's parent to point directly to the root (path compression)
+ parent[i] = find(parent[i]);
+ }
+
+ // Return the root (representative) of the set
+ return parent[i];
+ }
+
+ void union(int u, int v) {
+ // Find the root of each node
+ int rootU = find(u);
+ int rootV = find(v);
+
+ // If they belong to different sets, merge them
+ if (rootU != rootV) {
+ // Make rootV point to rootU — merge the two sets
+ parent[rootV] = rootU;
+
+ // Reduce the count of disjoint sets by 1
+ setCount--;
+ }
+ }
+
+ boolean inSameSet(int u, int v) {
+ return find(u) == find(v);
+ }
+
+ /*
+ This is a verbosity method, it's not a part of the core algorithm,
+ But it helps us provide more useful output.
+ */
+ Set getAnySet() {
+ int aRoot = find(0); // Get one of the two roots
+
+ Set set = new HashSet<>();
+ for (int i = 0; i < parent.length; i++) {
+ if (find(i) == aRoot) {
+ set.add(i);
+ }
+ }
+
+ return set;
+ }
+ }
+
+ private static class Graph {
+ private final List nodes;
+ private final List edges;
+
+ Graph(Collection nodeSet, List edges) {
+ this.nodes = new ArrayList<>(nodeSet);
+ this.edges = new ArrayList<>();
+ for (int[] e : edges) {
+ this.edges.add(new int[] {e[0], e[1]});
+ }
+ }
+
+ Graph copy() {
+ return new Graph(this.nodes, this.edges);
+ }
+
+ KargerOutput findMinCut() {
+ DisjointSetUnion dsu = new DisjointSetUnion(nodes.size());
+ List workingEdges = new ArrayList<>(edges);
+
+ Random rand = new Random();
+
+ while (dsu.setCount > 2) {
+ int[] e = workingEdges.get(rand.nextInt(workingEdges.size()));
+ if (!dsu.inSameSet(e[0], e[1])) {
+ dsu.union(e[0], e[1]);
+ }
+ }
+
+ int cutEdges = 0;
+ for (int[] e : edges) {
+ if (!dsu.inSameSet(e[0], e[1])) {
+ cutEdges++;
+ }
+ }
+
+ return collectResult(dsu, cutEdges);
+ }
+
+ /*
+ This is a verbosity method, it's not a part of the core algorithm,
+ But it helps us provide more useful output.
+ */
+ private KargerOutput collectResult(DisjointSetUnion dsu, int cutEdges) {
+ Set firstIndices = dsu.getAnySet();
+ Set firstSet = new HashSet<>();
+ Set secondSet = new HashSet<>();
+ for (int i = 0; i < nodes.size(); i++) {
+ if (firstIndices.contains(i)) {
+ firstSet.add(nodes.get(i));
+ } else {
+ secondSet.add(nodes.get(i));
+ }
+ }
+ return new KargerOutput(firstSet, secondSet, cutEdges);
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/randomized/KargerMinCutTest.java b/src/test/java/com/thealgorithms/randomized/KargerMinCutTest.java
new file mode 100644
index 000000000..876b6bf45
--- /dev/null
+++ b/src/test/java/com/thealgorithms/randomized/KargerMinCutTest.java
@@ -0,0 +1,114 @@
+package com.thealgorithms.randomized;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+public class KargerMinCutTest {
+
+ @Test
+ public void testSimpleGraph() {
+ // Graph: 0 -- 1
+ Collection nodes = Arrays.asList(0, 1);
+ List edges = List.of(new int[] {0, 1});
+
+ KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges);
+
+ assertEquals(1, result.minCut());
+ assertTrue(result.first().contains(0) || result.first().contains(1));
+ assertTrue(result.second().contains(0) || result.second().contains(1));
+ }
+
+ @Test
+ public void testTriangleGraph() {
+ // Graph: 0 -- 1 -- 2 -- 0
+ Collection nodes = Arrays.asList(0, 1, 2);
+ List edges = List.of(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0});
+
+ KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges);
+
+ assertEquals(2, result.minCut());
+ }
+
+ @Test
+ public void testSquareGraph() {
+ // Graph: 0 -- 1
+ // | |
+ // 3 -- 2
+ Collection nodes = Arrays.asList(0, 1, 2, 3);
+ List edges = List.of(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0});
+
+ KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges);
+
+ assertEquals(2, result.minCut());
+ }
+
+ @Test
+ public void testDisconnectedGraph() {
+ // Graph: 0 -- 1 2 -- 3
+ Collection nodes = Arrays.asList(0, 1, 2, 3);
+ List edges = List.of(new int[] {0, 1}, new int[] {2, 3});
+
+ KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges);
+
+ assertEquals(0, result.minCut());
+ }
+
+ @Test
+ public void testCompleteGraph() {
+ // Complete Graph: 0 -- 1 -- 2 -- 3 (all nodes connected to each other)
+ Collection nodes = Arrays.asList(0, 1, 2, 3);
+ List edges = List.of(new int[] {0, 1}, new int[] {0, 2}, new int[] {0, 3}, new int[] {1, 2}, new int[] {1, 3}, new int[] {2, 3});
+
+ KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges);
+
+ assertEquals(3, result.minCut());
+ }
+
+ @Test
+ public void testSingleNodeGraph() {
+ // Graph: Single node with no edges
+ Collection nodes = List.of(0);
+ List edges = List.of();
+
+ KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges);
+
+ assertEquals(0, result.minCut());
+ assertTrue(result.first().contains(0));
+ assertTrue(result.second().isEmpty());
+ }
+
+ @Test
+ public void testTwoNodesNoEdge() {
+ // Graph: 0 1 (no edges)
+ Collection nodes = Arrays.asList(0, 1);
+ List edges = List.of();
+
+ KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges);
+
+ assertEquals(0, result.minCut());
+ assertTrue(result.first().contains(0) || result.first().contains(1));
+ assertTrue(result.second().contains(0) || result.second().contains(1));
+ }
+
+ @Test
+ public void testComplexGraph() {
+ // Nodes: 0, 1, 2, 3, 4, 5, 6, 7, 8
+ // Edges: Fully connected graph with additional edges for complexity
+ Collection nodes = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8);
+ List edges = List.of(new int[] {0, 1}, new int[] {0, 2}, new int[] {0, 3}, new int[] {0, 4}, new int[] {0, 5}, new int[] {1, 2}, new int[] {1, 3}, new int[] {1, 4}, new int[] {1, 5}, new int[] {1, 6}, new int[] {2, 3}, new int[] {2, 4}, new int[] {2, 5}, new int[] {2, 6},
+ new int[] {2, 7}, new int[] {3, 4}, new int[] {3, 5}, new int[] {3, 6}, new int[] {3, 7}, new int[] {3, 8}, new int[] {4, 5}, new int[] {4, 6}, new int[] {4, 7}, new int[] {4, 8}, new int[] {5, 6}, new int[] {5, 7}, new int[] {5, 8}, new int[] {6, 7}, new int[] {6, 8}, new int[] {7, 8},
+ new int[] {0, 6}, new int[] {1, 7}, new int[] {2, 8});
+
+ KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges);
+
+ // The exact minimum cut value depends on the randomization, but it should be consistent
+ // for this graph structure. For a fully connected graph, the minimum cut is typically
+ // determined by the smallest number of edges connecting two partitions.
+ assertTrue(result.minCut() > 0);
+ }
+}