生动的普里姆算法详解

一:普里姆算法的介绍:

        针对无向图用来生成最小生成树的算法。

二:普里姆算法的步骤:

        起始条件:

        首先你有一个初始点v,所以此刻的点集V={v},边集S为空,同时准备两个数组,数组A记录所有点与起始点的权值(当然,如果不直接和起始点相连的话权值=无穷大),数组B用来存放距离自己最近的点,比如B[1]=2就是说距离1号点最近的点是2号点。然后算法开始。

        1.从所有点集里的点相连的边里,找到权值最小的那条边s,加入边集S,同时这条边相连的那个点也要加入点集V。

        2.遍历所有点,此刻还记得吗,我们的数组A里存放的可是所有点和起始点的距离权值,此刻我们的点集里多了一个点,于是我们遍历所有点的时候,是遍历所有点与这个新加的点的距离权值,如果每个点到新点的距离权值小于原来的值,那么,更新数组A,取小的值。

       让我们来系统的执行一次:

       一个孤苦伶仃的起始点小明看着周围的点点们都不和自己在一个集合里,于是很想找同伴,但是怎么找呢?它发现,自己和一些点身上绑着一条线(距离为线的权值),而和另一部分点则没有连线(距离为INF)(这些全都保存在数组A里,A['连线的点']=权值,A['不连线的点']=INF,也就是无穷大,姑且把A数组称为上帝面板。),很明显,当然是把距离自己最近的点拉进来啦!小明把最近的小华拽到了自己的集合里(完成了第一步),现在小华和小明有了同样的苦恼,当然也要扩充同伴啦!不过小明多了小华这么一个盟友,所以,和小华相连的点点们也可以被拽进来,于是更新上帝面板,凡是与小华相连的点到小华的距离小于A['此点']的点,都在上帝面板A上更新,用他们到小华的权值覆盖原值,同时此刻更新数组B,B['此点']=小华。到这里就完成了一次普里姆算法。

       那么,运行普里姆算法会导致形成环吗??这是不会的。我们会在设计算法的时候破坏这个潜在的可能性。

       总结来看,就是不断地找距离点集里的点权值最小的边,然后更新边集,扩充点集,然后不断的更新上帝面板和数组B

       下面看一下算法吧。

三.普里姆算法的代码实现:

void Prim(GraphClass<T> &gr, int v,T a[][MAXL])
{
	int lowcost[MAXL];//这就相当于数组A,上帝面板,它记录着非V顶点集到V顶点集的最短距离
	int closest[MAXL];//相当于数组B记录着距离V点集外某个点最近的V点集内的点
	int min, k;
	for (int i = 0;i < gr.G->n;i++)//初始化
	{
		lowcost[i] = a[v][i];
		closest[i] = v;
	}
	for (int i = 1;i < gr.G->n;i++)//找出n-1个顶点
	{
		min = INF;
		for (int j = 0;j < gr.G->n;j++)
			if (lowcost[j] != 0 && lowcost[j] < min)//lowcost[j]!=0很关键,因为为了防止出现环,我们需要去掉已经并入V顶点集的点。所以对于已经进入点集V的点,设置lowcost['已经进入点集V的点']=0,代码在下面第9行。
			{
				min = lowcost[j];
				k = j;
			}
        //执行完上面的循环,我们找到了距离V点集中的元素最近的点,k即为那个点,min即为那个值
        //可以说,closest数组里保存的就是一条边在V点集中的点,然后我们把他输出出来。
		cout << "边(" << closest[k] << ',' << k << ")权为" << min << endl;
        //这一步很关键,把走过(已经并入V集)的点在A数组中的值设置为0,这样上个循环就不会遍历这条记录。
		lowcost[k] = 0;
        //下面要重新设置上帝面板A里的值了,因为我们的V点集迎来了新成员,所以要重新设置非V点集到V点集的最短距离
		for(int j=0;j<gr.G->n;j++)
			if (a[k][j] != 0 && a[k][j] < lowcost[j])
			{
				lowcost[j] = a[k][j];
                //注意当这个if成立走到这一步的时候,就意味着,重新规划关系。这个时候,每个V点集外的点对于V点集的距离最近的点需要重置,很明显,下一步代码理所当然。
				closest[j] = k;
			}
	}
}

四:关于它:

       这个算法给我的感觉是,自己内心已经明白他的原理,但是从文字上很难描述的清楚,所以我也在尽力的让大家能够明白我的想法,但我的建议是,不要一字一句的对应着我的注释和代码走,而是从一两行给你启发的代码上入手自己往下想应该怎么做,然后到这里你可能就自己明白了,若是仍然模糊,则可以继续看我的解释和代码来想清除。这都是很顺其自然的。

  • 15
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CtrlZ1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值