【普里姆算法基本思想】从图中任取一个顶点作为一棵树。然后从与这棵树相连的边中选取一条最短(权值最小)的边,并将该边及其所连接的顶点也并入这个树中,此时便得到了具有两个顶点的树。接着从与这棵树相连的边中选取一条最短的边,并将该边及其所连接的顶点也并入这个树中,得到了了具有三个顶点的树。以此类推,直到图中所有顶点都被并入这棵树中为止,此时便得到了该图的最小代价生成树。
【普里姆算法用到的存储结构】用普里姆算法构造最小代价生成树的过程中,需要建立两个数组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)); } }