最小生成树——Prim算法理解

 背景:本文是在小甲鱼数据结构教学视频中的代码的基础上,添加详细注释而完成的。该段代码并不完整,仅摘录了核心算法部分,结合自己的思考,谈谈理解。

Prim算法理解:

如图(摘录自小甲鱼教学视频中的图片),是一个带有权值的连通网。

 根据上图可以列写出该连通网的邻接矩阵,为了方便直观的理解:

权值V0V1V2V3V4V5
V00615
V16053
V2150754
V35702
V43506
V54260

如上图所示,实际上Prim算法求解最小生成树的过程就是不断地寻找已走过顶点的最近顶点的过程(边权值最小)。

因此如上图所示,起点在V0点,寻找最近顶点,即V2点;找到V2点后,V2点作为当前顶点,继续寻找最近顶点,这时和已走过的顶点(V0、V2)直接连通的点共有4个:V1、V3、V4、V5,但是显然求解最小生成树不能重复进入已经走过的点,对于这个问题Prim算法采用的方法是将已经走过的点到任何点的权值都设定为0,然后在寻找最短边时,忽略权值为0点边。

这样当我们站在V2点处时,已走过的点到各个点之间的最短权值分别为:

权值V0V1V2V3V4V5
V0、V2050554

以上叙述的内容其实就是Prim算法的核心,即:①寻找最近点;②迭代lowcost数组。

在实际的算法实现中,就是通过这样一步一步迭代lowcost数组,然后在lowcost数组中寻找最小的权值,作为目标点,最终实现以最短路径遍历连通网。

代码及详细注释:

void MiniSpanTree_Prim(MGraph G)
{
	int min,i,j,k;
	/* 邻接数组 保存每一个顶点的邻接点(也就是上一个走过的点)的下标 */
	int adjvex[MAXWEX];
	/* 保存当前顶点向其他顶点的距离(其中已完成的顶点置零,表示不能再走) */
	int lowcost[MAXWEX];
	
	lowcost[0] = 0;
	adjvex[0] = 0;
	
	/* init */
	for(i=1;i<G.numVertexes;i++)
	{
		/* 将邻接矩阵第0行所有权值先加入数组 */
		/* 也就是将生成树的初始位置设定在该顶点 */
		/* 注意这个lowcost数组是逐级更新的:迭代到下一个点的时候,更新locwost数组 */
		/* lowcost数组更新原则:	已走过的点的lowcost值均保持0(即不再重复进入)
								将当前点到其他点的权值小于lowcost数组的,更新到lowcost数组中(为了保证每一次走的都是最短路径) */
		lowcost[i] = G.arc[0][i];
		/* 邻接数组初始化为0 */
		adjvex[i] = 0;
	}
	
	/* the real process creating the minispantree */
	for(i=1;i<G.numVertexes;i++)
	{
		/* min初始化为不可能的值(65535) */
		min = INFINITY;
		j = 1;
		k = 0;
		
		/* 遍历全部顶点 */
		while(j<G.numVertexes)
		{
			/* 找到当前顶点的可行边中权值最小的边 此即当前顶点的下一个邻接点 */
			if(lowcost[j] != 0 && lowcost[j] < min)
			{
				min = lowcost[j];
				k = j;
			}
			j++;
		}
		
		/* 打印点与点的邻接关系 遍历完成后这些邻接关系组合在一起就是最小生成树 */
		printf("(%d,%d)",adjvex[k],k);
		/* 这里很重要 */
		/* 将已经走过的顶点对应lowcost数组中的权值置0 已确保不再重复进入 */
		lowcost[k] = 0;
		
		/* for循环完成lowcost数组的更新(更新原则在lowcost数组的定义初有详细注释) */
		for(j=1;j<G.numVertexes;j++)
		{
			/* 到已走过的点的权值不更新(保持为0,两行之前的赋值完成) */
			/* 邻接矩阵中当前点到其他点的权值小于lowcost数组的更新 */
			if(lowcost[j] != 0 && G.arc[k][j] < lowcost[j])
			{
				lowcost[j] = G.arc[k][j];
				/* 邻接数组赋值(记录各点之间的邻接关系) */
				adjvex[j] = k;
			}
		}
	}
}

 

——cloud over sky

 ——2020/3/11

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值