BAEL-3406, refactor Kruskal algorithm by using more classes.
This commit is contained in:
parent
0df902da92
commit
103b04cb8e
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,20 +32,13 @@ public class Kruskal {
|
||||||
edgeList.sort(Collections.reverseOrder(Comparator.comparing(e -> graph.edgeValue(e).get())));
|
edgeList.sort(Collections.reverseOrder(Comparator.comparing(e -> graph.edgeValue(e).get())));
|
||||||
}
|
}
|
||||||
|
|
||||||
int totalEdges = edgeList.size();
|
|
||||||
int totalNodes = graph.nodes().size();
|
int totalNodes = graph.nodes().size();
|
||||||
|
CycleDetector cycleDetector = new CycleDetector(totalNodes);
|
||||||
int edgeCount = 0;
|
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();
|
MutableValueGraph<Integer, Double> spanningTree = ValueGraphBuilder.undirected().build();
|
||||||
for (int i = 0; i < totalEdges; i++) {
|
for (EndpointPair<Integer> edge : edgeList) {
|
||||||
EndpointPair<Integer> edge = edgeList.get(i);
|
if (cycleDetector.detectCycle(edge.nodeU(), edge.nodeV())) {
|
||||||
if (detectCycle(edge.nodeU(), edge.nodeV(), roots, sizes)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
spanningTree.putEdgeValue(edge.nodeU(), edge.nodeV(), graph.edgeValue(edge).get());
|
spanningTree.putEdgeValue(edge.nodeU(), edge.nodeV(), graph.edgeValue(edge).get());
|
||||||
|
@ -57,32 +50,4 @@ public class Kruskal {
|
||||||
return spanningTree;
|
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.MutableValueGraph;
|
||||||
import com.google.common.graph.ValueGraph;
|
import com.google.common.graph.ValueGraph;
|
||||||
import com.google.common.graph.ValueGraphBuilder;
|
import com.google.common.graph.ValueGraphBuilder;
|
||||||
|
import com.baeldung.algorithms.kruskal.Kruskal;
|
||||||
|
|
||||||
public class KruskalUnitTest {
|
public class KruskalUnitTest {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue