标签:
普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。
借用维基百科的定义就是:
从单一顶点开始,普里姆算法按照以下步骤逐步扩大树中所含顶点的数目,直到遍及连通图的所有顶点。
输入:一个加权连通图,其中顶点集合为V,边集合为E;
初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {};
重复下列操作,直到Vnew = V:
在集合E中选取权值最小的边(u, v),其中u为集合Vnew中的元素,而v则是V中没有加入Vnew的顶点(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
将v加入集合Vnew中,将(u, v)加入集合Enew中;
输出:使用集合Vnew和Enew来描述所得到的最小生成树。
其实算法的基本思想就是一个贪心的概念,选取一个结点当做源结点进行扩展,扩展方法就是选取源结点与其他结点之间权值最小的那个结点,因为如果构造一个最小生成树一定会包含源节点,包含源节点那么就一定会选取距离源结点最近的那条边包含进来.之后选取一个结点之后就构成了一个最小生成树集合,将所有结点分成了两部分,每次循环依次最小生成树集合都会增加一个结点,所以只需循环verNum-1次就可以得到最终结果.
其中要不断维护的就是一个最小边的数组lowcost,也就是从集合出发到其他结点的最小边长,以便筛选结点时使用,已经选进集合的结点i的lowcost[i]将被赋值为0.每次循环中选取min的过程其实可以使用优先队列来实现,自动排序,每次只需出队就可以了.
typedef struct { int arc[MAXVEX][MAXVEX]; int numVertexes; }MGraph; void prim(MGraph G) { int i,j;//循环变量 int min;//存放每次循环得出的边最小值 int k;//记录下一次要扩展的结点 int adjvex[MAXVEX];//存放全职最小的边的另一个结点,如adjvex[2] = 4;连接最小值边的为结点2到结点4. int lowcost[MAXVEX];//存放最小生成树集合中结点到每个结点的最小权值. lowcost[0] = 0;//将最小权值赋值为0说明该结点已经在最小生成树集合中 adjvex[0] = 0;//结点0到结点0的权值最小,所以adjvex[0] = 0. for (i = 0; i < G.numVertexes; i++)//初始化,结点0所有的边值赋值给最小全集数组 { lowcost[i] = G.arc[0][i]; adjvex[i] = 0; } for (i = 1; i < G.numVertexes; i++)//从1结点开始循环遍历,每循环依次往最小生成树集合中增加一个结点 { min = INFINITY; j = 1; k = 0; while(j < G.numVertexes)//循环查找集合向外扩展最小的边 { if (lowcost[j]!=0&&lowcost[j]<min)//lowcost=0代表结点已经在集合中 { min = lowcost[j];//记录最小边的值 k = j;//记录下一个要扩展的结点 } j++; } cout << "(" << adjvex[k] << ", " << k << ")" << " "; // 打印当前顶点边中权值最小的边 lowcost[k] = 0;// 将当前顶点的权值设置为0,表示此顶点已经完成任务 for(j = 1; j < G.numVertexes; j++)//扩展集合中的边,更新lowcost数组. { if(lowcost[j]!=0&&G.arc[k][j] < lowcost[j]) { lowcost[j] = G.arc[k][j]; adjvex[j] = k; } } } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/djd1234567/article/details/48091399