From 103b04cb8e94dc17702a10b4a343cf89d930e55f Mon Sep 17 00:00:00 2001 From: Gang Date: Sun, 22 Dec 2019 18:53:01 -0700 Subject: [PATCH] BAEL-3406, refactor Kruskal algorithm by using more classes. --- algorithms-miscellaneous-5/pom.xml | 6 +- .../algorithms/kruskal/CycleDetector.java | 72 +++++++++++++++++++ .../algorithms/kruskal/DisjointSetInfo.java | 28 ++++++++ .../baeldung/algorithms/kruskal/Kruskal.java | 43 ++--------- .../algorithms/kruskal/KruskalUnitTest.java | 1 + 5 files changed, 108 insertions(+), 42 deletions(-) create mode 100644 algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/kruskal/CycleDetector.java create mode 100644 algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/kruskal/DisjointSetInfo.java diff --git a/algorithms-miscellaneous-5/pom.xml b/algorithms-miscellaneous-5/pom.xml index 83a30f420c..95036da775 100644 --- a/algorithms-miscellaneous-5/pom.xml +++ b/algorithms-miscellaneous-5/pom.xml @@ -35,9 +35,9 @@ ${tradukisto.version} - com.google.guava - guava - 28.1-jre + com.google.guava + guava + 28.1-jre diff --git a/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/kruskal/CycleDetector.java b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/kruskal/CycleDetector.java new file mode 100644 index 0000000000..dec0bcdd85 --- /dev/null +++ b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/kruskal/CycleDetector.java @@ -0,0 +1,72 @@ +package com.baeldung.algorithms.kruskal; + +import java.util.ArrayList; +import java.util.List; + +public class CycleDetector { + + List nodes; + + public CycleDetector(int totalNodes) { + initDisjointSets(totalNodes); + } + + public boolean detectCycle(Integer u, Integer v) { + Integer rootU = pathCompressionFind(u); + Integer rootV = pathCompressionFind(v); + if (rootU.equals(rootV)) { + return true; + } + unionByRank(rootU, rootV); + return false; + } + + private void initDisjointSets(int totalNodes) { + nodes = new ArrayList<>(totalNodes); + for (int i = 0; i < totalNodes; i++) { + nodes.add(new DisjointSetInfo(i)); + } + } + + private Integer find(Integer node) { + Integer parent = nodes.get(node).getParentNode(); + if (parent.equals(node)) { + return node; + } else { + return find(parent); + } + } + + private Integer pathCompressionFind(Integer node) { + DisjointSetInfo setInfo = nodes.get(node); + Integer parent = setInfo.getParentNode(); + if (parent.equals(node)) { + return node; + } else { + Integer parentNode = find(parent); + setInfo.setParentNode(parentNode); + return parentNode; + } + } + + private void union(Integer rootU, Integer rootV) { + DisjointSetInfo setInfoU = nodes.get(rootU); + setInfoU.setParentNode(rootV); + } + + private void unionByRank(int rootU, int rootV) { + DisjointSetInfo setInfoU = nodes.get(rootU); + DisjointSetInfo setInfoV = nodes.get(rootV); + int rankU = setInfoU.getRank(); + int rankV = setInfoV.getRank(); + if (rankU < rankV) { + setInfoU.setParentNode(rootV); + } else { + setInfoV.setParentNode(rootU); + if (rankU == rankV) { + setInfoU.setRank(rankU + 1); + } + } + } + +} diff --git a/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/kruskal/DisjointSetInfo.java b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/kruskal/DisjointSetInfo.java new file mode 100644 index 0000000000..ecdc42587a --- /dev/null +++ b/algorithms-miscellaneous-5/src/main/java/com/baeldung/algorithms/kruskal/DisjointSetInfo.java @@ -0,0 +1,28 @@ +package com.baeldung.algorithms.kruskal; + +public class DisjointSetInfo { + + private Integer parentNode; + private int rank; + + DisjointSetInfo(Integer nodeNumber) { + setParentNode(nodeNumber); + setRank(1); + } + + public Integer getParentNode() { + return parentNode; + } + + public void setParentNode(Integer parentNode) { + this.parentNode = parentNode; + } + + public int getRank() { + return rank; + } + + public void setRank(int rank) { + this.rank = rank; + } +} 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 index 62b260c71e..da405679d1 100644 --- 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 @@ -14,7 +14,7 @@ import java.util.Set; public class Kruskal { public ValueGraph minSpanningTree(ValueGraph graph) { - + return spanningTree(graph, true); } @@ -32,20 +32,13 @@ public class Kruskal { edgeList.sort(Collections.reverseOrder(Comparator.comparing(e -> graph.edgeValue(e).get()))); } - int totalEdges = edgeList.size(); int totalNodes = graph.nodes().size(); + CycleDetector cycleDetector = new CycleDetector(totalNodes); 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)) { + for (EndpointPair edge : edgeList) { + if (cycleDetector.detectCycle(edge.nodeU(), edge.nodeV())) { continue; } spanningTree.putEdgeValue(edge.nodeU(), edge.nodeV(), graph.edgeValue(edge).get()); @@ -57,32 +50,4 @@ public class Kruskal { 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 index e944d2894c..a7206c6cd0 100644 --- 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 @@ -9,6 +9,7 @@ import org.junit.Test; import com.google.common.graph.MutableValueGraph; import com.google.common.graph.ValueGraph; import com.google.common.graph.ValueGraphBuilder; +import com.baeldung.algorithms.kruskal.Kruskal; public class KruskalUnitTest {