无向图的最小代价生成树之普里姆算法

【普里姆算法基本思想】从图中任取一个顶点作为一棵树。然后从与这棵树相连的边中选取一条最短(权值最小)的边,并将该边及其所连接的顶点也并入这个树中,此时便得到了具有两个顶点的树。接着从与这棵树相连的边中选取一条最短的边,并将该边及其所连接的顶点也并入这个树中,得到了了具有三个顶点的树。以此类推,直到图中所有顶点都被并入这棵树中为止,此时便得到了该图的最小代价生成树。

【普里姆算法用到的存储结构】用普里姆算法构造最小代价生成树的过程中,需要建立两个数组vset[]和lowcost[]。vset[i]=1表示顶点i已经被并入生成树中,vset[i]=0表示顶点i还没有被并入生成树中。lowcost[]数组中存放当前生成树到剩余各个顶点最短边的权值。即,当前生成树这一个整体到其余各个顶点的权值的最小值(因为当前生成树到其余各个顶点的边可能存在多条,固然可能存在多个权值,但是lowcost[]中只存权值的最小值),而不是针对生成树中的某一个顶点。

【普里姆算法执行过程】从某一个顶点V0开始构造最小生成树:① 将V0到其他顶点的所有边作为当前的候选边;② 重复以下步骤n-1次,使得其余n-1个顶点被并入到生成树中;(1)从候选边中挑选出权值最小的边输出,并将与该边另一端相连的顶点V并入到生成树中;(2)考查所有剩余顶点Vi,如果(V,Vi)的权值比lowcost[Vi]小,则用V,Vi)的权值更新lowcost[Vi]。

【普里姆算法时间复杂度分析】普里姆算法的时间复杂度为O(n2)。可见普里姆算法的时间复杂度只与图中顶点有关系,与边数没有关系,因此普里姆算法适用于稠密图(我的理解就是点相对于边来说要少)。

【普里姆算法Java代码】

public class Main{
	public int prim(int[][] graph,int v0){
		int[] vset = {0,0,0,0,0};
		int lowcost[] = {0,0,0,0,0};
		int min_index = 0;
		int v = v0;
		int sum = 0;
		//初始化lowcost数组
		for (int i = 0; i < graph.length; i++) {
			lowcost[i] = graph[v0][i];
		}
		//将顶点v0并入生成树
		vset[v0] = 1;	
		//重复以下步骤n-1次,直到所有顶点都被并入生成树
		for (int i = 1; i < graph.length; i++) {
			int min = 10;
			//选出当前生成树到其余顶点最短边中最短的一条
			for (int j = 0; j < graph.length; j++) {
				if (vset[j] == 0 && lowcost[j] < min) {
					min = lowcost[j];
					min_index = j;
				}
			}
			//将最短边连接的顶点并入生成树
			vset[min_index] = 1;
			v = min_index;
			sum += min;
			System.out.println("第"+i+"次加入到生成树中的顶点为:"+v);
			//考查所有剩余顶点Vi,如果(V,Vi)的权值比lowcost[Vi]小,则用V,Vi)的权值更新lowcost[Vi]
			for (int k = 0; k < graph.length; k++) {
				if (vset[k] == 0 && graph[v][k] < lowcost[k]) {
					lowcost[k] = graph[v][k];
				}
			}
		}
		return sum;
	}
	
    public static void main(String[] args) {
        Main main = new Main();
        int[][] graph = {{10,5,1,2,10},
				 {5,10,3,10,4},
				 {1,3,10,6,2},
				 {2,10,6,10,3},
				 {10,4,2,3,10}};
        System.out.println("最小生成树的代价为:"+main.prim(graph, 0));
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_36378917/article/details/80562627