- 任选图中一个顶点加入U1
- 选取U1中点与U2中点连接成的最小的邻边,将该边原来在U2中的那个顶点加入U1,将此边加入 最小生成树中
- 重复步骤2直到边数等于顶点数减一
//普利姆算法:将图的所有顶点分成两个顶点集,一个存放树的结点,另一个存放未在生成树中的点
//每次找已经是树节点的最小边,因为它是运用了切分定理所以不会形成回路不用判断
/*
* 类描述:普利姆算法求最小生成树
*@author @Lqx
*/
public class Prim {
public static final int M = -1;
// 存储图的邻接矩阵
static int[][] map= {
{ M, 9, M, M, 16, 2 },
{ 9, M, 14, M, M, 2 },
{ M, 14, M, 7, M, 21 },
{ M, M, 7, M, 5, 3 },
{ 16, M, M, 5, M, 7 },
{ 2, 2, 21, 3, 7, M }
};
// boolean visited[] = new boolean[map.length];
// 存放树中的点,初始化为false,false的所有点为不在生成树中的结点的一个点集,true的所有点为在生成树中结点的点集
static boolean[] add = new boolean[map.length];
static int[][] edge = new int[map.length][map.length]; //存放树枝
static int[][] prim(int[][] a, int origin) {
int vexnumber = a.length;
for (int i = 0; i < vexnumber; i++) {
add[i] = false;
}
add[origin] = true; // 第一个点加入
int begin=0; //存放起点下标
int tempmin = -1;
int end = -1;
int number = 0;
while (number != vexnumber - 1) {
// 只要边数等于顶点数-1就结束
for (int i = 0; i < vexnumber; i++) {
if (add[i]) {
// 如果在树节点集中,就找与它相邻的最小边,这里因为对每个在树中的顶点进行标记,所以不会将自环加入树中
for (int j = 0; j < vexnumber; j++) {
if (a[i][j] != M && add[j]==false) {
//必须是存在通路,并且该点还不在生成树中
if (tempmin == -1 || a[i][j] < tempmin) {
// 找最小边
tempmin = a[i][j]; // 暂时存放最小边
begin=i;
end = j;
}
}
}
}
}
edge[begin][end] = tempmin; // 加入边集
a[begin][end] = -1; // 让原本的边无效
add[end] = true; // 把该点加入点集中
tempmin=-1; //重新让它恢复原值不然会导致后面出错
number++; //计算树枝的数量(边数)
}
return edge;
}
public static void main(String[] args) {
int[][] b = prim(map, 0);
System.out.println("该图的最小生成树结点和树枝情况如下:");
for (int i = 0; i < b.length; i++) {
for (int j = 0; j < b.length; j++) {
if (b[i][j] != 0) {
System.out.println( "v"+(i+1) + "-->v"+(j+1) + ": " + b[i][j] + "(权值)");
}
}
}
}
}
- 结果(输出结果并不是按照生成过程的顺序输出而是按照二维数组遍历顺序):