普利姆算法(Prim):
图论中的一种算法,用来在加权连通图中构造最小代价生成树,何为最小代价生成树呢,也就是通过此算法生成的树,不但包括了原连通图中的所有节点,而且保证了所有边的权值之和最小。
算法原理:
现有一个加权联通图,顶点集合为V,边的集合为E,构造最小代价生成树时,Vnew代表生成树的顶点集合,Enew代表生成树的边的集合,最小代价生成树的过程如下:
1.初始化,Vnew = {V0},Enew = {},即选择从顶点V0开始构造最小代价生成树(也可以选择其他任意的顶点)
2.在集合E中选取权值最小的边<u,v>,其中u为集合Vnew中的元素,但是v不是集合Vnew中的元素,将这个顶点v和边分别添加到Vnew和Enew中
重复步骤2,直到V = Vnew,也就是最小代价生成树中的顶点和原图中的顶点完全一样时,算法结束
实现代码如下:
//int[][] G就是传入的图
//G[i][j]表示顶点i和顶点j之间相连边的权值,如果G[i][j] = 0,表示顶点ij不相邻
public void prim(int[][] G){
//这是数组用来保存每个顶点是否被遍历过
boolean[] isMark = new boolean[G.length];
//用来保存已经遍历过的顶点
ArrayList<Integer> result = new ArrayList<>();
//初始随意选择一个顶点作为起始点,这里选择顶点0
result.add(0);
isMark[0] = true;
while(result.size()<G.length){
//distance用来寻找最小权值
int distance = Integer.MAX_VALUE;
//u表示已遍历顶点中和未遍历顶点有最小权值的一个已经在Vnew中的顶点
int u = -1;
//u表示未遍历顶点中和以遍历顶点有最小权值的一个未在Vnew中的顶点
int v = -1;
for(int i = 0;i<result.size();i++){
int minu = result.get(i);
for(int j=0;j<G.length;j++){
//当前顶点未被遍历,而且顶点minu和顶点j联通,
//而且他们之间边的权值小于之前的最小权值时,对distance,u,v进行更新
if(!isMark[j]){
if(G[minu][j]!=0&&G[minu][j]<distance){
distance = G[minu][j];
u = minu;
v = j;
}
}
}
}
//将新的顶点加入到result中,最后result中存放的是按顺序加入最小代价生成树中的每一个顶点
isMark[v] = true;
result.add(v);
}
}
prim算法在边数较多的图中有着更高的效率