码迷,mamicode.com
首页 > 编程语言 > 详细

剖析prim最小生成树算法

时间:2015-08-18 14:07:39      阅读:220      评论:0      收藏:0      [点我收藏+]

标签:

在上一篇博客中,已经用代码实现了这个算法。只是我认为从算法到代码实现,这是一个很大的过渡,不喜欢教科书式的顺理成章的过渡,虽然下面写的不知所云,虽然我很菜。

看完上篇博客中代码,想想其中一些问题,
1、如何将图的相互关系,用合适的数据结构来表示
2、如何搜索某一节点周围的权值路径
3、如何将新的节点加入到新的搜索库中。

第一个问题
技术分享
对于这个图关系,用什么样的数据结构来表示,这里有两两之间的关系,能想到的树、队列、等等,好像都不能,
找到了一篇博客
http://blog.csdn.net/zscacm/article/details/7209098
研究图的表示方法的。本质上就是相互之间的关系太复杂,没有固定的前驱和后继。常用的数组能将这种关系表示出来,

第二个问题
按照prim算法的第一步,
选择一个点作为入口(假设为A),将A加入备选结合,找出与这个集合相连的节点,并找出其中最小的权值,

技术分享
如何将这种思想程序化,已经建立图的二维数组存储方式,从数组中可以看出,与A相连的节点是B和C,就是数组中第一行所体现的关系。
这里好多问题,有点乱,为什么要找这种关系,这种关系的本质是什么。prim的核心思想是什么。

所以抛开前面 重新看看prim算法的过程

有一种算法过程步骤:
1.将第一个点放入最小生成树的集合中(标记visit[i]=1意思就是最小生成树集合)。
2.初始化lowcost[i]为跟1点相连(仅仅相连)的边的权值(lowcost[i]不是这个点的最小权值!在以后会逐步更新)。
3.枚举n个顶点
4.将找出来的最小权值的边的顶点加入最小生成树的集合中(标记visit[i]= 1),权值想加。
5.更新lowcost[j]集合。
关键步骤:实质就是每在最小生成树集合中加入一个点就需要把这个点与集合外的点比较,不断的寻找两个集合之间最小的边
6.循环上述步骤,指导将全部顶点加入到最小生成树集合为止。
技术分享
看了上面这个图,想想这个过程是一个循环过程,那么循环的主体是什么,
每一次循环都是在将一个点加入某个集合,而决定加入这个点的原因就是在所有的点中,它到集合的权重是最小的。
技术分享
一直循环,将权重最小的点加入到这个集合,直到所有点都已被加入。

如何表示集合的概念?什么是集合?集合就是具有某些属性一直的对象在一起。最简单的就是用变量标记,比如每个对象都包含一个成员变量,这个成员变量用于说明此对象的属性。而在此处,可以用一个数组来体现这个集合,数组下标表示是哪个对象,而对应数组元素则表示是否属于集合元素

如何获取集合与节点之间的关系权重?如果出现下面这种情况
技术分享

也就是说集合与某一节点有不止一个权重路径,prim算法是需要更新结合与节点的权值路径,保证是最短的,然后再去寻找下一个加入结合的节点。

如何更新或者说当一个新的结点加入集合后,如何找出新的与结合相连的节点。

比如
技术分享
当前集合包含节点1,与其相连的节点为2、3、4
找到下一个节点是,3
然后新的集合产生,而与新的集合相连的节点少了3、多了5.
技术分享
而多出来的节点,实际是由新加入的节点3带来的。所以要扩充更新这个连接节点库,就是看看节点3的节点库。

所以总结一下prim的过程就是

1)将第一个节点加入集合,更新这个集合的外节点库,
2)从外节点库中找出权重最小的节点,加入集合,更新这个集合的外节点库
3)循环2,直到所有节点都加入到集合中。

下面是重新整理的一段代码,分别对应上面的步骤

vector < int > que;
用于存放集合外节点库,
vector < int > flag;
用于标记集合内的节点

第一步:
将第一个节点加入集合,更新这个集合的外节点库,

loc=0;
flag[loc]=1; //将位置0的节点加入集合
for(i=0;i

int stree(int map[N][N],int num)
{
 int i=0;
 int j=0;
 int min;
 int loc;
 int minsum=0;
 vector < int > que;
 vector < int > flag;
 que.resize(num);
 flag.resize(num);
 for(i=0;i<num;++i)
  que[i]=MAX;

 loc=0;
 flag[loc]=1;
 for(i=0;i<num;++i)
 {
  if(i!=loc)
   que[i]=map[loc][i];
 }


 for(i=0;i<num-1;++i)
 {
  min=MAX;
  for(j=0;j<num;++j)
  {
   if(min>que[j] && flag[j]!=1)
   {
    min=que[j];
    loc=j;
   }
  }
  minsum+=min;

  flag[loc]=1;

  for(j=0;j<num;++j)
  {
   if(flag[j]!=1 && map[loc][j]<que[j])
    que[j]=map[loc][j];
  }

 }
 return minsum;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

剖析prim最小生成树算法

标签:

原文地址:http://blog.csdn.net/u010442328/article/details/47750665

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!