算法过程:
辅助数组closedge来记录V-U中各个顶点在U中的最近邻接点以及对应边的权值。
class Closedge {
int nearvex;//对于顶点Vi属于V-U,nearex存储vi在U的最近邻接点,即在所有关联Vi和U中顶点的边中权值最小者所关联的U中顶点
int minw;//对于顶点Vi属于V-U,minw存储Vi到U中最近邻接点的边上的权
boolean mark;//用于标志Vi是否已被选入生成树,即是否已经加入U
}
- 对每个顶点Vi属于V,在辅助数组中存在一个分量closedge[i],它包括3个域nearverx,minw和mark。其中,1,mark为布尔类型,用于在算法执行中标志Vi是否已被选入生成树,即是否已经加入U。若Vi属于U,mark值为true,否则Vi属于V-U,mark值为false。2,对于顶点Vi属于V-U,nearvex存储Vi在U中的最近邻接点,即在所有关联Vi和U中顶点的边中权值最小者所关联的U中顶点。换句话说,Vi尚未入选U,此时可存在若干条边使它与U中顶点相邻接,若边(Vk,Vi)是其中权值最小者,那么closedge[i].nearvex=k。3,对于顶点Vi属于V-U,minw存储Vi到U中最近邻接点的边上的权,即closedge[i].minw=min{w(j,i)},由于(Vk,Vi)最小,显然closedge[i].minw=w(k,i).
算法过程
(1)初始化。
初始状态下,TE中没有边,即TE={ },集合U中只有一个初始顶点Vs,即U={Vs},令closedge[s].nearvex=-1,closedge[s].minw=0,closedge[s].mark=true.同时,对所有顶点Vi属于V-U,将closedge[i]均初始化为Vi到Vs的信息:1,若Vi不是Vs的邻接点,closedge[i].nearvex=-1,closedge[i].minw=Integer.MAX_VALUE.(可为无穷),closedge[i].mark=false;2,若Vi是Vs的邻接点,令closedge[i].nearvex=s,closedge[i].min=w(s,i),closedge[i].mark=false.,其中w(s,i)为顶点Vs到顶点Vi的权值。
(2)重复(2.1)和(2.2),不断从V-U中选择顶点加入U,直至U=V。
(2.1)求最小生成树的下一个顶点。
在V-U中选择生成树的下一个 顶点Vk满足closedge[k].minw=min{closedge[i].minw},Vk是离U最近的顶点,将Vk从V-U中移除加入U,更新clsoedge[k].mark=true,同时将边closedge[k].nearvex加入TE。
(2.2)修正V-U中顶点的最近邻接点
如图所示,由于U中新加入了顶点Vk,对每一个Vi属于V-U而言,Vi在U中最近邻接点便多了一种可能,就是Vk,所以要对Vi的最近邻接点进行修正。比较minw与W(k,i)的大小,minw是Vi与原最近邻接点之间边的权值,W(k,i)是边(Vk,Vi)的权值,比较结果有2中情况
1.minw<=w(k,i),此时Vi的最近邻接点不变,closedge[i].nearvex和closedge[i].minw亦不变
2.minw>w(k,i),此时Vi的最近邻接点更新为Vk,closedge[i].nearvex更新为k,closedge[i].minw更新为w(k,i).
代码如下:
import java.util.Scanner;
/*
Prim算法之所以是正确的,主要基于一个判断:对于任意一个顶点v,
连接到该顶点的所有边中的一条最短边(v, vj)必然属于最小生成树(即任意
一个属于最小生成树的连通子图,从外部连接到该连通子图的所有边中的一条最短边必然属于最小生成树)
*/
public class Prim {
public static void main(String[] args) {
/*-------------初始化---------------*/
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();//n个顶点
Closedge[] closedge = new Closedge[n];
for (int i = 0; i < n; i++)
closedge[i] = new Closedge();
int i = 0, j = 0, k = 0;
int[][] G = new int[n][n];//图的矩阵存储,连通为正数,不连通为0
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
G[i][j] = sc.nextInt();
}
System.out.println("图创建完毕!");
int s = 0;
/
closedge[s].nearvex = -1;
closedge[s].minw = 0;
closedge[s].mark = true;
for (i = 0; i < G.length; i++) {
if (i != s) {
if (G[s][i] <500) {//G[s][i]连通 //若Vi是Vs的邻接点
closedge[i].nearvex = s;
closedge[i].minw = G[s][i];
closedge[i].mark = false;
} else { //若Vi不是Vs的邻接点
closedge[i].nearvex = -1;
closedge[i].minw = G[s][i];//0?
closedge[i].mark = false;
}
}
}
/*------------依次产生最小生成树除Vs以外的其余n-1个顶点------------*/
for (i = 1; i < G.length; i++) {//求生成树的下一个顶点
//在V-U中选择离U最近的顶点
int minw = Integer.MAX_VALUE;
for (j = 0; j < G.length; j++) {
if ((!closedge[j].mark) && closedge[j].minw < minw) {//j节点没被选入生成树且j节点的权值小于上一个权值
k = j;
minw = closedge[j].minw;//选出最小的权值
}
}
System.out.println("顶点 " + closedge[k].nearvex + "---> 顶点 " + k + " 权值:" + minw);
closedge[k].mark = true;//Vk加入U
for (j = 0; j < G.length; j++) {//对V-U中每一个顶点,修正它在U中的最近邻接点
if ((!closedge[j].mark) && (G[k][j] < closedge[j].minw)) {
closedge[j].nearvex = k;
closedge[j].minw = G[k][j];
}
}
}
}
}
class Closedge {
int nearvex;//对于顶点Vi属于V-U,nearex存储vi在U的最近邻接点,即在所有关联Vi和U中顶点的边中权值最小者所关联的U中顶点
int minw;//对于顶点Vi属于V-U,minw存储Vi到U中最近邻接点的边上的权
boolean mark;//用于标志Vi是否已被选入生成树,即是否已经加入U
}
ps:代码中500应为不连通的具体情况