普利姆算法

来源:互联网 发布:逆袭网络剧完整版 编辑:程序博客网 时间:2024/04/30 05:49
算法思想:可取图中任意一个顶点V作为生成树的根,之后若要往生成树上添加顶点W,则在顶点V和W之间必定存在一条边。并且该边的权值在所有连通顶点V和W之间的边中取值最小。

一般情况下,假设n个顶点分成两个集合:U(包含已落在生成树上的结点)和V-U(尚未落在生成树上的顶点),则在所有连通U中顶点和V-U中顶点的边中选取权值最小的边

 C语言代码如下:

[cpp] view plaincopyprint?
  1. //最小生成树 普里姆算法    采用邻接矩阵存储  
  2. void MiniSpanTree(MGraph *G)  
  3. {  
  4.     int min, i, j, k;  
  5.     int adjvex[MaxVex];     //保存相关顶点下标  
  6.     int lowcost[MaxVex];    //保存相关顶点间边的权值  
  7.     lowcost[0] = 0;         //初始化第一个权值为0,即V0加入生成树  
  8.     adjvex[0] = 0;          //初始化第一个顶点下标为0  
  9.   
  10.     for (i=1; i<G->numVertexes; ++i)  
  11.     {  
  12.         lowcost[i] = G->arc[0][i];  
  13.         adjvex[i] = 0;              //将v0顶点与之有边的权值存入数组  并初始化都为v0的下标  
  14.     }  
  15.   
  16.     for (i=1; i<G->numVertexes; ++i)  
  17.     {  
  18.         min = INFINITY;  
  19.   
  20.         j = 1;  
  21.         k = 0;  
  22.   
  23.         while (j<G->numVertexes)  
  24.         {  
  25.             //如果两个顶点之间存在边并且权值小于min  
  26.             if (lowcost[j]!=0 && lowcost[j]<min)  
  27.             {  
  28.                 min = lowcost[j];  
  29.                 k = j;  
  30.             }  
  31.   
  32.             ++j;  
  33.         }  
  34.         printf("(%d, %d)", adjvex[k], k);   //输出当前顶点边中权值最小的边  
  35.         lowcost[k] = 0;                     //将当前顶点的权值设为0,表示此顶点已经完成任务  
  36.         for (j=1; j<G->numVertexes; ++j)  
  37.         {  
  38.             if (lowcost[j]!=0 && G->arc[k][j]<lowcost[j])  
  39.             {  
  40.                 lowcost[j] = G->arc[k][j];  
  41.                 adjvex[j] = k;  
  42.             }  
  43.         }  
  44.     }  
  45. }  


 首先是变量的定义,min在每次循环中都存放着lowcost数组中最小的权值。

adjvex与lowcost数组中的下标分别对应了该图中的顶点,如下标为1对应了第2个顶点(顶点的序号从0开始)。

例如adjvex[3] = 5  lowcost[3] = 8即表示序号为5的顶点(即第6个顶点)到序号为3(两个数组的下标都为3 即第4个顶点)的顶点的边的权值为8

接着初始化lowcost[0]与adjvex[0]为0,即表示第0号结点加入生成树,lowcost[i] = 0表示第i个结点加入到生成树中

然后 一个循环将adjvex数组的值全都置为0并且将v0到其他顶点的权值都存入lowcost数组中。

一个包含所有顶点的大循环,所有的工作都在该循环体内完成

①假设现在是第一次循环 即第一个顶点加入生成树,第23行~33行,求得所有与该结点相邻的顶点的边上的最小的权值,并将该权值存放min中,而与其相邻的那个顶点的序号存入k中。即找到一个顶点k并且v0到k的权值是所有v0的邻接点中最小的。

/输出当前顶点边中权值最小的边  即输出adjvex[k], k 因为是第一次循环 所有adjvex[k] = 0, k即刚才所得到的那个权值最小的相邻的顶点的序号。即表示adjvex[k]号顶点到k号顶点

③lowcost[k] = 0; 表示 第k号顶点已经加入到生成树种

④第36行~43行  if (lowcost[j]!=0 && G->arc[k][j]<lowcost[j])  如果顶点j没有加入生成树 并且k顶点到j顶点的权值要小于对应的lowcost数组中第j个元素的权值,那么就讲该权值存入Lowcost数组并将j存入adjvex中。也就是说,当我加入了一个k顶点到生成树中以后,那么生成树中必然会多一些k顶点与其邻接点的边出来,那么我要看下这些边上的权值是否有小于lowcost数组中对应位置上的值(初始状态lowcost数组中的值都是v0到各个顶点的边的权值),如果小于那么就说明顶点k到顶点j的边的权值要比V0到j的边的权值小。我们当然要保存这个结果,那么就修改adjvex[j] = k  lowcost[j] =  G->arc[k][j];  即k顶点到j顶点的权值为 G->arc[k][j];  

以后每次加入一个新的顶点都要看其与其邻接点的边上的权值是否要小于lowcost数组中对应顶点的权值。如果小于就修改

然后找到Lowcost数组中最小的权值 并将其与顶点输出

原创粉丝点击