BAEL-3406, refactor Kruskal algorithm by using more classes.

This commit is contained in:
Gang 2019-12-22 18:53:01 -07:00
parent 0df902da92
commit 103b04cb8e
5 changed files with 108 additions and 42 deletions

View File

@ -35,9 +35,9 @@
<version>${tradukisto.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.1-jre</version>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.1-jre</version>
</dependency>
<dependency>

View File

@ -0,0 +1,72 @@
package com.baeldung.algorithms.kruskal;
import java.util.ArrayList;
import java.util.List;
public class CycleDetector {
List<DisjointSetInfo> 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);
}
}
}
}

View File

@ -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;
}
}

View File

@ -14,7 +14,7 @@ import java.util.Set;
public class Kruskal {
public ValueGraph<Integer, Double> minSpanningTree(ValueGraph<Integer, Double> 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<Integer> roots = new ArrayList<>(totalNodes);
List<Integer> sizes = new ArrayList<>(totalNodes);
for (int i = 0; i < totalNodes; i++) {
roots.add(i);
sizes.add(1);
}
MutableValueGraph<Integer, Double> spanningTree = ValueGraphBuilder.undirected().build();
for (int i = 0; i < totalEdges; i++) {
EndpointPair<Integer> edge = edgeList.get(i);
if (detectCycle(edge.nodeU(), edge.nodeV(), roots, sizes)) {
for (EndpointPair<Integer> 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<Integer> 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<Integer> roots, List<Integer> 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<Integer> roots, List<Integer> sizes) {
Integer rootU = find(u, roots);
Integer rootV = find(v, roots);
if (rootU.equals(rootV)) {
return true;
}
unionBySize(rootU, rootV, roots, sizes);
return false;
}
}

View File

@ -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 {