关于神奇的最小生成树---Prim算法详解

最小生成树—Prim算法详解

首先我们来解释一下什么是最小生成树:
在这里插入图片描述
显然这是一个带权值的图,即网结构。所谓的最小成本就是n个顶点,用(n-1)条边把一个连通图连接起来,并且使权值的和最小,我们把构造连通图的最小代价生成树称为最小生成树。

Prim算法

先把这幅图的邻接矩阵给大家:
(其实这里应该把深度优先搜索—临界矩阵的算法给出来,来求出我们需要的邻接矩阵,但是术业有专攻,我们只讲Prim,还有因为我懒,所以就直接给大家一个矩阵)

    v0  v1  v2  v3  v4  v5  v6  v7  v8 
v0 { 0  10  ∞   ∞   ∞   11   ∞   ∞   ∞} 
v1 { 10  0  18  ∞   ∞   ∞   1612} 
v2 { ∞   ∞  0  22   ∞   ∞    ∞   ∞   8}
v3 { ∞   ∞  22  0   20  ∞    ∞  16  21}
v4 { ∞   ∞  ∞  20   0   267}
v5 { 11  ∞  ∞   ∞   26  0   17   ∞   ∞}
v6 {16  ∞   ∞   ∞   17   0  19}
v7 { ∞   ∞  ∞  16   719   0}
v8 {12  8  21   ∞   ∞   ∞    ∞   0}

话不多说,先上代码;

#define INF 65535           //代表无穷大 
1.void MinispanTree-Prim(Mgraph G)
2.{
3.	int min,i,j,k;
4.	int low[G.vex];          //定义一个数组,存储权值
5.	int vex[G.vex];          //存储顶点变化,请认真注意数组变化
6.	//初始化 
7.	vex[0]=0;                //初始化第一个权值为0,即V0加入生成树   
8.	low[0]=0;                //初始化第一个顶点下标为0
9.	//以下代码见下详解 
10.	for(i=1;i<G.vex;i++)
11.	{
12.		vex[i]=0;
13.		low[i]=G.arc[0][i];   
14.	 } 
15.	 
16.	 for(i=1;i<G.vex;i++)        //循环次数 
17.	 {
18.	    min=INF;                 
19.	    k=0;
20.	 	for(j=1;j<G.vex;j++)
21.		 {
22.		 	if(low[j]!=0 && low[j]<min)
23.	 	    {
24.	 		   min=low[j];
25.	 		   k=j;
26.		    } 
27.		  } 
28.		  printf("(%d,%d)\n",vex[k],k);
29.	 	low[k]=0;
30.	 	for(j=1;j<G.vex;j++)
31.	 	{
32.	 		if(low[j]!=0 && G.arc[k][j]<low[j])
33.	 		{
34.	 			low[j]=G,arc[k][j];
35.	 			vex[j]=k;
36.			 }
37.		 }	 
38.	 }
39.} 

现在我们来把上面这段不算太长代码拆开一步一步来看:

10.	for(i=1;i<G.vex;i++)   //这段代码作用就是初始化,简单明了
11.	{
12.		vex[i]=0;
13.		low[i]=G.arc[0][i];   
14.	 } 

顶点**vex[ ]**数组初始化结果

v0v1v2v3v4v5v6v7v8
000000000

初始化权值数组**low[ ]**结果

j012345678
low01011

注意此处low数组的结果与邻接矩阵第v0行数据相同,所以我们可以明确low数组的作用是为了暂时存储权值
注意看,prim的核心算法要来了,我在这会贴出很多图

for(i=1;i<G.vex;i++)        //循环次数 ,因为有9个顶点,所以我们需要循环(9-1)次,因为V0点我们默认
                           //已经进入了最小生成树
	 {
	    min=INF;          //INF是最大值,代表无穷大
	    k=0;
	 	for(j=1;j<G.vex;j++)
		 {
		 	if(low[j]!=0&&low[j]<min)
	 	    {
	 		   min=low[j];     //找出权值数组中最小的权值,并且记录下标
	 		   k=j;
		    } 
		  } 
		  printf("(%d,%d)\n",vex[k],k); 
		 ................
	 }

我认为这段代码的作用就是体现出了“最小”二字,变量min在权值low数组中寻找最小权值,其目的就是为了找到一个最小的加入生成树。
经过遍历查找,我们发现在low数组中,最小的权值是10,其j值是1,即k=1,所以这里的输出应该是(01);

现在来看这段代码中的重中之重,low[k]=0表示这个顶点的权值已经加入最小生成树了,所以我们让他为0,表示已被使用;

for(i=1;i<G.vex;i++)        //循环次数 
	 {
	   .............
	 	low[k]=0;        
	 	for(j=1;j<G.vex;j++)

	 	{
	 		if(low[j]!=0&&G.arc[k][j]<low[j])
	 		{
	 			low[j]=G,arc[k][j];
	 			vex[j]=k;
			 }
		 }	
		 
	 }

此时我们已经找到一个顶点V1加入了最小生成树,那么下一步应该是做什么呢?
当然是找下一个邻接点了,毫无疑问,这个点的权值也应该是最小的,所以此时就应该找V1点的邻接点里的最小权值,此时的K=1,现在让我们进入这个神奇的for循环:

先来看这个if的判断条件,当权值为0时,我们就认为他已经加入了最小生成树,注意此处是low权值数组,一定要看清;在V1的邻接点的权值中,我们找到一些权值,而这些权值小于V0的邻接点权值,碰到更小的权值,我们的做法肯定是把大的踢出去啊,把小的拉进来;
v0点权值数组

j012345678
low01011

记得low[K]=0

V1点100181612

经过比较,我们发现, j=2以及j=6,j=8时,v1点邻接点的权值比v0邻接点的权值小,所以我们把v1点的小权值放入原来的low数组中,于是新的low数组就生成了:

j012345678
low0018111612

我们到底把哪些点加入了新的权值数组中了呢?我们这时引入顶点vex[ ]数组,记录加入low权值数组的点的顶点坐标
于是vex[ ]数组变为了:

v0v1v2v3v4v5v6v7v8
001000101

到这里第一次循环就结束了,上面就是prim的基本算法以及思路,接下里我将给出后两次循环的k值,low权值数组变化以及顶点vex数组的变化
第二次循环:

low数组变化

j012345678
low0018111612

经过比较权值大小得到
K=5
记得low[K]=0

V5点1126017

新的low数组

j012345678
low00182601612

vex数组

v0v1v2v3v4v5v6v7v8
001050101

第三次循环:

low数组变化

j012345678
low00182601612

经过比较权值大小得到
K=8
记得low[K]=0

V8点128210

新的low数组

j012345678
low00821260160

vex数组

v0v1v2v3v4v5v6v7v8
008850101
剩下的就靠大家去慢慢推了,这个算法需要慢慢去推,因为第一次写博客,有很多东西不是很熟练,不能完全表达出来,各位见谅,如果对各位有帮助,不能三连,那就记得点赞!!!!!!我们下次见!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值