普里姆算法c语言(详细解读)

首先我们要知道普里姆算法是为了求最小二生成树。

这里不做过多介绍,直接上思想和代码。

一.具体过程:

(1)初始化U={v}。v到其他顶点的所有边为候选边;  

(2)重复以下步骤n-1次,使得其他n-1个顶点被加入到U中:  

  a.从候选边中挑选权值最小的边输出,设该边在V-U中的顶点是k,将k加入U中;  

   b.考察当前V-U中的所有顶点j,修改候选边:若(j,k)的权值小于和和顶点j关联的候选边,则用(k,j)取代后者作为候选边。

上述过程大家可能看不懂,简单点讲就是先选取一个起始点a将a看成一个整体U,然后将其余的点看成另一个整体V-U,从和a邻接的边中选择一个权值最小的边,并加入这个边的结点,这两个结点和边就是新的U,然后再找与这个U相连的边中权值最小的边,并加入与此边相连的结点,重复上述步骤,将所有点加入即可构成最小生成树。

二.图解:

例如生成下图的最小生成树:

1.首先,我们选择起始点为结点0,与0邻接的边有(0,1),(0,5)。比较容易发现两者权值小的是10,所以加入结点5.得到如图:

2.将结点0和5以及权值为10的边(0,5)看成一个系统。找到与这个系统邻接的边(0,1),(5,4),比较两者的权值,容易发现权值最小的为25,因此加入边(5,4),同时加入结点4和边(5,4)。

 

3.将上图看成一个整体,它的邻接边有(0,1)28,(4,6)24,(4,3)22三者权值最小的为边(4,3),所以加入结点3.

4.将0,5,4,3以及相关的边看成一个整体,与其邻接的边有(0,1)28,(4,6)24,(3,6)18,(3,2)12,四个边中权值最小的边是(3,2),所以加入结点2以及边(3,2)。

 

 5.与4中所构成的整体邻接的边有(0,1)28,(4,6)24,(3,6)18,(2,1)16,四者中权值最小的边为(2,1),所以加入结点1以及边(2,1)。

 6.与5中所构成的整体邻接的边有(4,6)24,(3,6)18,(1,6)14,三者中权值最小的边为(1,6),所以加入结点6以及边(1,6)。至此所有点已经加入,也就生成了最小生成树。

 那么我们如何用代码实现呢?

1.由于Prim算法中需要频繁的地取一条条边的权值,所以我们采用邻接矩阵更加合适。通过邻接矩阵我们不仅可以了解到结点与结点之间的关系,同时也可以了解权值的具体情况。

首先我们建立两个数组一个为lowcost[]:用于存储权值情况,另一个为closest[]:用于记录最小边的情况。我们规定lowcost[i]=0,表示已经加入了我们的整体中,即加入了U中。lowcost[i]!=0表示还没有加入,属于V-U中。当生成了最小生成树时,lowcost[]数组中全部为0.

2.还是以这个图为列:

它的邻接矩阵为:(这里我们用@代替无穷符号)

0123456
0028@@@10@
128016@@@14
2@16012@@@
3@@12022@18
4@@@2202524
510@@@250@
6@14@1824@0

图解执行过程(字可能有点小,丑,慢慢仔细看):

 接下来就是具体代码执行过程:

在此之前我们先了解邻接矩阵的定义:
 

define MAXV<最大顶点个数>
#define INF 32767//定义无穷 
typedef struct
{
	int no;             //顶点编号
	InfoTYpe info;      //顶点的其他信息(这里目前用不到) 
}VertexType;            //顶点的类型 
typedef struct
{
	int edges[MAXV][MAXV];   //邻接矩阵数组 
	int n,e;                 //顶点数,边数 
	VertexType vexs[MAXV];   //存放顶点信息 
}MatGraph;                   //完整的图邻接矩阵类型 

算法实现:

void Prim(MatGraph g,int v)    //g是邻接矩阵,V是顶点编号
{
   int lowcost[MAXV];
   int mindist;
   int closest[MAXV],i,j,k;
   for(i=0;i<g.n;i++)         //邻接矩阵中n是顶点数(这可以看邻接矩阵的定义)
   {
   	 lowcost[i]=g.edges[v][i];
   	 closest[i]=v;
   }                         //给数组lowcost[]与数组closest初始化 
   for(i=1;i<g.n;i++)        //找出n-i个顶点 
   {
   	mindist=INF;
   	for(j=0;j<g.n;j++)      //在(V-U)中找出离U最近的顶点 
   	 if(lowest[j]!=0&&lowest[j]<mindist)
   	   {
		mindist=lowcost[j];
   	 	k=j;                //K记录最近的顶点的编号 
	   }	
	printf("边(%d,%d)权为:%d\n",closest[k],k,mindist);     //输出最小的一条生成边
	lowcost[k]=0;                                   //标记顶点K已经加入 
	for(j=0;j<g.n;j++)                             //对(V-U)中的顶点j进行调整
	if(lowcost[j]!=0&&g.edges[k][j]<lowcost[j])
		{
			lowcost[j]=g.edges[k][j];
			closest[j]=k;                      //修改数组lowcost[]和closest[] 
		} 
    }
}

Over!!!!!!

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值