图-最小生成树之Prim算法

普利姆算法(Prim)

1).输入:一个加权连通图,其中顶点集合为V,边集合为E;

2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;

3).重复下列操作,直到Vnew = V:

a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);

b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;

4).输出:使用集合Vnew和Enew来描述所得到的最小生成树

整个代码分为三个部分:初始化 - 找最小权值 - 更新调整lowcost数组

示例:

说明:

  • adjvex数组存放的是对应顶点的前驱,即当选定v2为权最小加入最小生成树时,adjvex[2]=0.在代码的一开始adjvex全部置为0,因为v0是算法起始点。
  • lowcost置为0时表示的是已经将对应顶点加入最小生成树,比如lowcost[0]=0,即表示生成树集合U={V0},当然了,当U=V(顶点集)时,算法结束。
  • 这里很多循环是从1开始的,因为v0已经被加入了U集(lowcost[0]=0),从0开始浪费一次循环,当然如果从0开始也不会报错。注意第一个for循环是在初始化v0到其他各顶点的权值,从i=1开始时因为从v0到v0的边没有意义,当然了如果你把对角线设置为0的话,其实从0开始也没区别。
  • 在第一次for循环里,初始化所有顶点对应adjvex都为0,因为从0开始找最小权值,找到了的话他的前驱一定也只能是v0。
#include "邻接矩阵.h"
#define INFINITY 65535
void Prim(MGraph G){
	int min, i, j, k; /*k为最小值对应的下标*/
	int adjvex[MAXVEX]; /*保存的是每次循环开始的那个起始点下标*/
	int lowcost[MAXVEX];/*表示相关顶点之间的权值*/
	lowcost[0] = 0; /*表示下标为0的顶点即V0已经加入最小生成树*/
	adjvex[0] = 0; /*从顶点V0开始*/
	for(i = 1; i < G.numVertexes; i++){
		lowcost[i] = G.arc[0][i];/*将与V0顶点有边的顶点全部存入数组*/
		adjvex[i] = 0; /*全部初始化为V0的下标0*/

	}
	/*至此完成初始化工作 开始循环构造最小生成树*/
	for(i = 1; 1 < G.numVertexes; i++){
		min = INFINITY; /*初始化最小值为∞*/
		j = 1; k = 0;
        /*从1开始的原因已经在上面说明部分指出了,因为从0开始没有意义,V0已经在U集里了*/
        /*这个while循环每次从更新过的lowcost数组中找出了为0(即已经加入最小生成树)的最小值,找到之后对应的数组索引就是下一个要加入U集的顶点,把它赋给k*/
		while(j < G.numVertexes){
			if(lowcost[j]!=0 && lowcost[j] < min){
				/*如果权值不为0(尚未被纳入最小生成树)且权值小于min*/
				min = lowcost[j];
				k = j;
			}
			j++;
		}
		printf("(%d %d)", adjvex[k], k);/*打印当前顶点边中权值最小的边*/
		lowcost[k] = 0; /*k顶点已经被纳入最小生成树*/
		/*更新 新起始点到各顶点之间的权值 起始点已经从0变掉了,所以应该比较从0到各顶点的权值与从新起始点到各顶点的权值,取小者*/
		for(j = 1; j < G.numVertexes; j++){
			if(lowcost[j] != 0 && G.arc[k][j] < lowcost[j])
				lowcost[j] = G.arc[k][j];
				adjvex[j] = k; /*同样的,更新对应的起始点下标,如果值更新比如v2->v4对应权值由v0->v4的xxx更新为更小的为yyy,则adjvex[4]=2;如果值没有更新的话,比如v0->v3权值还是更小的那一个,那他的adjvex也不更新,还是adjvex[3]=0,表示他的起始顶点为v0*/
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值