diff --git a/algorithms-miscellaneous-5/pom.xml b/algorithms-miscellaneous-5/pom.xml
index 2f530958e3..83a30f420c 100644
--- a/algorithms-miscellaneous-5/pom.xml
+++ b/algorithms-miscellaneous-5/pom.xml
@@ -34,6 +34,11 @@
tradukisto
${tradukisto.version}
+
+ com.google.guava
+ guava
+ 28.1-jre
+
org.assertj
diff --git a/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/kruskal/Kruskal.java b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/kruskal/Kruskal.java
new file mode 100644
index 0000000000..62b260c71e
--- /dev/null
+++ b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/kruskal/Kruskal.java
@@ -0,0 +1,88 @@
+package com.baeldung.algorithms.kruskal;
+
+import com.google.common.graph.EndpointPair;
+import com.google.common.graph.MutableValueGraph;
+import com.google.common.graph.ValueGraph;
+import com.google.common.graph.ValueGraphBuilder;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+
+public class Kruskal {
+
+ public ValueGraph minSpanningTree(ValueGraph graph) {
+
+ return spanningTree(graph, true);
+ }
+
+ public ValueGraph maxSpanningTree(ValueGraph graph) {
+ return spanningTree(graph, false);
+ }
+
+ private ValueGraph spanningTree(ValueGraph graph, boolean minSpanningTree) {
+ Set> edges = graph.edges();
+ List> edgeList = new ArrayList<>(edges);
+
+ if (minSpanningTree) {
+ edgeList.sort(Comparator.comparing(e -> graph.edgeValue(e).get()));
+ } else {
+ edgeList.sort(Collections.reverseOrder(Comparator.comparing(e -> graph.edgeValue(e).get())));
+ }
+
+ int totalEdges = edgeList.size();
+ int totalNodes = graph.nodes().size();
+ int edgeCount = 0;
+ List roots = new ArrayList<>(totalNodes);
+ List sizes = new ArrayList<>(totalNodes);
+ for (int i = 0; i < totalNodes; i++) {
+ roots.add(i);
+ sizes.add(1);
+ }
+
+ MutableValueGraph spanningTree = ValueGraphBuilder.undirected().build();
+ for (int i = 0; i < totalEdges; i++) {
+ EndpointPair edge = edgeList.get(i);
+ if (detectCycle(edge.nodeU(), edge.nodeV(), roots, sizes)) {
+ continue;
+ }
+ spanningTree.putEdgeValue(edge.nodeU(), edge.nodeV(), graph.edgeValue(edge).get());
+ edgeCount++;
+ if (edgeCount == totalNodes - 1) {
+ break;
+ }
+ }
+ return spanningTree;
+ }
+
+ private Integer find(Integer x, List roots) {
+ Integer root = roots.get(x);
+ if (!root.equals(x)) {
+ roots.set(x, find(root, roots));
+ }
+ return roots.get(x);
+ }
+
+ private void unionBySize(Integer rootU, Integer rootV, List roots, List sizes) {
+ Integer total = sizes.get(rootU) + sizes.get(rootV);
+ if (sizes.get(rootU) < sizes.get(rootV)) {
+ roots.set(rootU, rootV);
+ sizes.set(rootV, total);
+ } else {
+ roots.set(rootV, rootU);
+ sizes.set(rootU, total);
+ }
+ }
+
+ private boolean detectCycle(Integer u, Integer v, List roots, List sizes) {
+ Integer rootU = find(u, roots);
+ Integer rootV = find(v, roots);
+ if (rootU.equals(rootV)) {
+ return true;
+ }
+ unionBySize(rootU, rootV, roots, sizes);
+ return false;
+ }
+}
diff --git a/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/kruskal/KruskalUnitTest.java b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/kruskal/KruskalUnitTest.java
new file mode 100644
index 0000000000..e944d2894c
--- /dev/null
+++ b/algorithms-miscellaneous-5/src/test/java/com/baeldung/algorithms/kruskal/KruskalUnitTest.java
@@ -0,0 +1,66 @@
+package com.baeldung.algorithms.kruskal;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+import com.google.common.graph.MutableValueGraph;
+import com.google.common.graph.ValueGraph;
+import com.google.common.graph.ValueGraphBuilder;
+
+public class KruskalUnitTest {
+
+ private MutableValueGraph graph;
+
+ @Before
+ public void setup() {
+ graph = ValueGraphBuilder.undirected().build();
+ graph.putEdgeValue(0, 1, 8.0);
+ graph.putEdgeValue(0, 2, 5.0);
+ graph.putEdgeValue(1, 2, 9.0);
+ graph.putEdgeValue(1, 3, 11.0);
+ graph.putEdgeValue(2, 3, 15.0);
+ graph.putEdgeValue(2, 4, 10.0);
+ graph.putEdgeValue(3, 4, 7.0);
+ }
+
+ @Test
+ public void givenGraph_whenMinimumSpanningTree_thenOutputCorrectResult() {
+ final Kruskal kruskal = new Kruskal();
+ ValueGraph spanningTree = kruskal.minSpanningTree(graph);
+
+ assertTrue(spanningTree.hasEdgeConnecting(0, 1));
+ assertTrue(spanningTree.hasEdgeConnecting(0, 2));
+ assertTrue(spanningTree.hasEdgeConnecting(2, 4));
+ assertTrue(spanningTree.hasEdgeConnecting(3, 4));
+ assertEquals(graph.edgeValue(0, 1), spanningTree.edgeValue(0, 1));
+ assertEquals(graph.edgeValue(0, 2), spanningTree.edgeValue(0, 2));
+ assertEquals(graph.edgeValue(2, 4), spanningTree.edgeValue(2, 4));
+ assertEquals(graph.edgeValue(3, 4), spanningTree.edgeValue(3, 4));
+
+ assertFalse(spanningTree.hasEdgeConnecting(1, 2));
+ assertFalse(spanningTree.hasEdgeConnecting(1, 3));
+ assertFalse(spanningTree.hasEdgeConnecting(2, 3));
+ }
+
+ @Test
+ public void givenGraph_whenMaximumSpanningTree_thenOutputCorrectResult() {
+ final Kruskal kruskal = new Kruskal();
+ ValueGraph spanningTree = kruskal.maxSpanningTree(graph);
+
+ assertTrue(spanningTree.hasEdgeConnecting(0, 1));
+ assertTrue(spanningTree.hasEdgeConnecting(1, 3));
+ assertTrue(spanningTree.hasEdgeConnecting(2, 3));
+ assertTrue(spanningTree.hasEdgeConnecting(2, 4));
+ assertEquals(graph.edgeValue(0, 1), spanningTree.edgeValue(0, 1));
+ assertEquals(graph.edgeValue(1, 3), spanningTree.edgeValue(1, 3));
+ assertEquals(graph.edgeValue(2, 3), spanningTree.edgeValue(2, 3));
+ assertEquals(graph.edgeValue(2, 4), spanningTree.edgeValue(2, 4));
+
+ assertFalse(spanningTree.hasEdgeConnecting(0, 2));
+ assertFalse(spanningTree.hasEdgeConnecting(1, 2));
+ assertFalse(spanningTree.hasEdgeConnecting(3, 4));
+ }
+}