算法思路非常简单
- 用并查集的思想,N个点形成N个集合
- 对图中的K条边按照权重从小到大排序
- 取一条最小的边,如果边的两个顶点不属于同一集合,则采用这条边,同时合并两个顶点所在的集合
- 如果两个顶点属于同一集合,则会形成回路,此时该舍弃该边,继续寻找下一条
public class Kruskal {
static final int N = Integer.MAX_VALUE;
public static void main(String[] args) {
int[][] map = {
{N, 23, N, N, N, 28, 36},
{23, N, 20, N, N, N, 1},
{N, 20, N, 15, N, N, 4},
{N, N, 15, N, 3, N, 9},
{N, N, N, 3, N, 17, 16},
{28, N, N, N, 17, N, 25},
{36, 1, 4, 9, 16, 25, N}
};
kruskal(map);
}
static class Edge{
int weight;
int point1;
int point2;
public Edge(int weight, int point1, int point2) {
this.weight = weight;
this.point1 = point1;
this.point2 = point2;
}
}
private static void kruskal(int[][] map) {
int n = map.length;
PriorityQueue<Edge> edges = new PriorityQueue<>((Comparator.comparingInt(o -> o.weight)));
for (int i = 0; i <n ; i++) {
for (int j = i+1; j <n ; j++) {
edges.add(new Edge(map[i][j], i, j));
}
}
int[] parent = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
while (!edges.isEmpty()) {
Edge edge = edges.poll();
if(getParent(edge.point1,parent) == getParent(edge.point2,parent))
continue;
System.out.println("连接"+edge.point1+"--"+edge.point2);
parent[getParent(edge.point2,parent)] = getParent(edge.point1,parent);
}
}
private static int getParent(int index, int[] parent) {
while (parent[index] != index) {
index = parent[index];
}
return index;
}
}
输出:
连接1--6
连接3--4
连接2--6
连接3--6
连接4--5
连接0--1
与Prim算法中用的同一张图,最后的生成树也是一样的(但最小生成树不一定是唯一的)
参考
《趣学算法》