在一个连通网图中,构造连通网的最小代价生成树称为最小生成树(Minimum Cost Spanning Tree)。
普里姆(Prim)算法
步骤:
- 生成树的点集为U,边集为Te,设初始点集合为图中任意一点u~0~,Te为空;
- 在所有u∈U、v∈V-U的边(u,v)中找一条权值最小的边并入集合Te,同时该点并入集合U中;
- 对每个点重复以上操作,直到U=V,此时Te即为最小生成树。
Prim算法代码示例(图以邻接矩阵表示):
//构建最小生成树,matrix为无向网图邻接矩阵
private static void MiniSpanTree_Prim(){
int min,i,j,k;
int[] adjvex = new int[MAXVEX];
int[] lowcost = new int[MAXVEX];
lowcost[0] = 0;
adjvex[0] = 0;
for(i = 1; i < matrix.getVerNum(); i++){
lowcost[i] = matrix.getArc()[0][i];
adjvex[i] = 0;
}
for (i = 1; i < matrix.getVerNum(); i++){
min = INFINITY;
j = 1;
k = 0;
while (j < matrix.getVerNum()){
if(lowcost[j] != 0 && lowcost[j] < min){
min = lowcost[j];
k = j;
}
j++;;
}
System.out.print(adjvex[k]+", "+k + " -> ");
lowcost[k] = 0;
for (j = 1; j < matrix.getVerNum(); j++){
if(lowcost[j] != 0 && matrix.getArc()[k][j] < lowcost[j]){
lowcost[j] = matrix.getArc()[k][j];
adjvex[j] = k;
}
}
}
}
Prim算法时间复杂度为O(n^2^)
克鲁斯卡尔(Kruskal)算法
步骤:
- 将边集数组按权值从大小到大排序;
- 依次找出权值最小的边,若不出现环路,就将其加入最小生成树。
实现代码如下:
//构造最小生成树
private static void MiniSpanTree_Kruskal(){
Edge[] edges = new Edge[matrix.getEdgeNum()];
int i,n,m;
int l = 0;
int[] parent = new int[MAXVEX]; //判断是否发生回路
for(i = 0; i < matrix.getVerNum(); i++){
for(int j = i; j < matrix.getVerNum(); j++){
if(matrix.getArc()[i][j] > 0 && matrix.getArc()[i][j] < INFINITY){
edges[l] = new Edge(i,j,matrix.getArc()[i][j]);
l++;
}
}
}
Arrays.sort(edges, Comparator.comparingInt(o -> o.weight));
for (i = 0; i < matrix.getVerNum(); i++){
parent[i] = 0;
}
for (i = 0; i < matrix.getEdgeNum(); i++){
n = Find(parent, edges[i].start);
m = Find(parent,edges[i].end);
if(n != m){
parent[n] = m;
System.out.print(edges[i].start+", "+edges[i].end+", "+edges[i].weight+" -> ");
}
}
}
//查找连线顶点的尾部下标
private static int Find(int[] parent, int f){
while (parent[f] > 0)
f = parent[f];
return f;
}
Find函数时间复杂度为O(lge),循环e次,时间复杂度为O(elge)。