最小生产数讲解
克鲁斯卡尔(Kruskal)算法从另一途径求网的最小生成树。其基本思想是:假设连通网G=(V,E),令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),概述图中每个顶点自成一个连通分量。在E中选择代价最小的边,若该边依附的顶点分别在T中不同的连通分量上,则将此边加入到T中;否则,舍去此边而选择下一条代价最小的边。依此类推,直至T中所有顶点构成一个连通分量为止
思路
package graph;
import java.util.*;
public class Code04_Kruskal {
// 定义一个并查集
public class UnionFind{
// key 某一个节点, value key节点往上的节点
private HashMap<Node, Node> fathermap;
// key 某一个集合的代表节点, value key所在集合的节点个数
private HashMap<Node, Integer> sizeMap;
public UnionFind() {
this.fathermap = new HashMap<>();
this.sizeMap = new HashMap<>();
}
// 初始化集合
public void makeSets(Collection<Node> nodes) {
fathermap.clear();
sizeMap.clear();
for (Node node : nodes) {
fathermap.put(node, node);
sizeMap.put(node, 1);
}
}
// 找到代表节点,压缩路径
private Node findFather(Node n) {
Stack<Node> stack = new Stack<>();
while (n != fathermap.get(n)) {
stack.push(n);
n = fathermap.get(n);
}
while (!stack.isEmpty()) {
fathermap.put(stack.pop(), n);
}
return n;
}
// 判断两节点是否在同一集合内
public boolean isSameSet(Node a, Node b) {
return findFather(a) == findFather(b);
}
// 合并两节点所在集合
public void union(Node a, Node b) {
Node aHead = findFather(a);
Node bHead = findFather(b);
if (aHead != bHead) {
int aSize = sizeMap.get(aHead);
int bSize = sizeMap.get(bHead);
Node big = aSize >= bSize ? aHead : bHead;
Node small = big == aHead ? bHead : aHead;
fathermap.put(small, big);
sizeMap.put(big, aSize + bSize);
sizeMap.remove(small);
}
}
}
private class MyComparator implements Comparator<Edge> {
@Override
public int compare(Edge o1, Edge o2) {
return o1.weight - o2.weight;
}
}
// 主函数
public Set<Edge> kruskalMST(Graph graph) {
// 创建并查集
UnionFind unionFind = new UnionFind();
// 初始化并查集
unionFind.makeSets(graph.nodes.values());
// 创建优先级队列,权重越小越靠前
PriorityQueue<Edge> edges = new PriorityQueue<>(new MyComparator());
// 将边加入到优先级队列
for (Edge edge : graph.edges) {
edges.offer(edge);
}
Set<Edge> result = new HashSet<>();
// 遍历优先级队列,使用并查集构建最小生成树
while (!edges.isEmpty()) {
Edge edge = edges.poll();
if (!unionFind.isSameSet(edge.from, edge.to)) {
result.add(edge);
unionFind.union(edge.from, edge.to);
}
}
return result;
}
}