最小生成树的PRIM算法(c++实现)
在网络搭建中,最小生成树有其广泛的应用.本文是作者学习了PRIM算法实现最小生成树之后的笔记体会.欢迎指正批评.
1.概述
设G =(V,E)是无向连通带权图,即一个网络。E中每条边(v,w)的权为c[v][w]。如果G的子图G’是一棵包含G的所有顶点的树,则称G’为G的生成树。生成树上各边权的总和称为该生成树的耗费。在G的所有生成树中,耗费最小的生成树称为G的最小生成树。
网络的最小生成树在实际中有广泛应用。例如,在设计通信网络时,用图的顶点表示城市,用边(v,w)的权c[v][w]表示建立城市v和城市w之间的通信线路所需的费用,则最小生成树就给出了建立通信网络的最经济的方案。
最小生成树性质:
设G=(V,E)是连通带权图,U是V的真子集。如果(u,v)属于E,且u属于U,v属于V-U,且在所有这样的边中,(u,v)的权c[u][v]最小,那么一定存在G的一棵最小生成树,它以(u,v)为其中一条边。这个性质有时也称为MST性质。
2.PRIM算法
设G=(V,E)是连通带权图,V={1,2,…,n}。
构造G的最小生成树的Prim算法的基本思想是:首先置S={1},然后,只要S是V的真子集,就作如下的贪心选择:选取满足条件i属于S,j属于V-S,且c[i][j]最小的边,将顶点j添加到S中。这个过程一直进行到S=V时为止。
在这个过程中选取到的所有边恰好构成G的一棵最小生成树。
利用最小生成树性质和数学归纳法容易证明,上述算法中的边集合T始终包含G的某棵最小生成树中的边。因此,在算法结束时,T中的所有边构成G的一棵最小生成树。
例如,对于右图中的带权图,按Prim算法选取边的过程如下页图所示。
按Prim算法选取边的过程如下页图所示。
在上述Prim算法中,还应当考虑如何有效地找出满足条件i在S中,j也在V-S中,且权c[i][j]最小的边(i,j)。实现这个目的的较简单的办法是设置2个数组closest和lowcost。
在Prim算法执行过程中,先找出V-S中使lowcost值最小的顶点j,然后根据数组closest选取边(j,closest[j]),最后将j添加到S中,并对closest和lowcost作必要的修改。
用这个办法实现的Prim算法所需的计算时间为O(n2).
以下是我参考<计算机算法分析与设计>王晓东第三版的代码设计的程序.
#include <iostream> #define MAXINT 6 using namespace std; //声明一个二维数组,C[i][j]存储的是点i到点j的边的权值,如果不可达,则用1000表示 //借此二维数组来表示一个连通带权图 int c[MAXINT][MAXINT]={{1000,6,1,5,1000,1000},{6,1000,5,1000,3,1000},{1,5,1000,5,6,4},{5,1000,5,1000,1000,2},{1000,3,6,1000,1000,6},{1000,1000,4,2,6,1000}}; void Prim(int n) { int lowcost[MAXINT];//存储S中到达对应的其它各点的最小权值分别是多少 int closest[MAXINT];//closest[]数组保存的是未在S中的点所到达S中包含的最近的点是哪一个,如:closest[i]=1表示i最靠近的S中的点是1 bool s[MAXINT];//bool型变量的S数组表示i是否已经包括在S中 int i,k; s[0]=true;//从第一个结点开始寻找,扩展 for(i=1;i<=n;i++)//简单初始化 { lowcost[i]=c[0][i]; closest[i]=0;//现在所有的点对应的已经在S中的最近的点是1 s[i]=false; } cout<<"0->"; for(i=0;i<n;i++) { int min=1000;//最小值,设大一点的值,后面用来记录lowcost数组中的最小值 int j=1; for(k=1;k<=n;k++)//寻找lowcost中的最小值 { if((lowcost[k]<min)&&(!s[k])) { min=lowcost[k];j=k; } } cout<<j<<" "<<"->"; s[j]=true;//添加点j到集合S中 for(k=1;k<=n;k++)//因为新加入了j点,所以要查找新加入的j点到未在S中的点K中的权值是不是可以因此更小 { if((c[j][k]<lowcost[k])&&(!s[k])){lowcost[k]=c[j][k];closest[k]=j;} } } } int main() { //输入初始化数组 cout<<"请输入初始权值数组:"<<endl; for(int i=0;i<MAXINT;i++) { for(int j=0;j<MAXINT;j++) { // cout<<"please enter c["<<i<<"]["<<j<<"]:"; // cin>>c[i][j]; cout<<c[i][j]<<"\t"; // cout<<endl; } cout<<endl; } Prim(MAXINT-1); return 0; }