BAEL-3406, refactor Kruskal algorithm by using more classes.
This commit is contained in:
parent
0df902da92
commit
103b04cb8e
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
Loading…
Reference in New Issue