【算法4】4.3.6.最小生成树-Kruskal算法
Kruskal算法(又称克鲁斯卡尔算法)。
其思想是:首先将图看成是由一个个孤立的顶点组成,然后按边的权重从小到大处理,将顶点连接起来,
并且要保证选取的边不会跟已选取的边构成环,当选出 V - 1 条边时最小生成树生成完成。
Kruskal 算法每次选取出最小的横切边(横切边就是连接最小生成树及其补集的边),是贪心算法的体现。
Kruskal 算法实现:
- 使用优先队列将边按从小到大的顺序弹出
- 使用 union-find 算法 判断是否有环产生
- 使用队列来保存最小生成树的边
/**
* 使用克鲁斯卡尔算法找出加权连通图的最小生成树
* */
public class KruskalMST implements MST {
private Queue<Edge> mst;
public KruskalMST(EdgeWeightedGraph G) {
mst = new Queue<>(); // 使用优先队列保存最小生成树的边
MinPQ<Edge> pq = new MinPQ<>(); // 使用优先队列按边从小到大顺序处理
UnionFind unionFind = new UnionFind(G.V()); // 使用 union-find 算法检测是否会产生环
// 将所有边添加到优先队列
for (Edge e : G.edges()) {
pq.add(e);
}
// 开始生成最小生成树
while (!pq.isEmpty() && mst.size() < G.V() - 1) {
Edge e = pq.remove();
int v = e.either();
int w = e.other(v);
if (unionFind.connected(v, w)) {
continue;
}
mst.add(e);
unionFind.union(v, w);
}
}
}
性能分析:Kruskal 算法一般比 Prim 算法慢,因为在处理每条边时除了两种算法都要完成优先队列操作之外,Kruskal 算法还需要进行一次 union-find
操作。