《数据结构与算法》——图的最小生成树之普利姆算法(Prime)总结

《数据结构与算法》——图的最小生成树之普利姆算法(Prime)总结

在考研中,图的应用所包含的一个重要部分被称为最小生成树,其中教材中给出了两个算法,Prime算法和kruskal算法。这是两个思想完全不同的算法,下面即为关于这两个算法中的Prime算法的总结。

本来以为这部分模拟起来很容易,算法实现起来比较麻烦,所以估计不会考大题,最多就是考一个模拟过程。但是!!!去年的考题中就出现了这个算法的题目,说来惭愧,我一直以为那道题考的是Dijkstra算法。我抱着押它不考大题的心态去见我导师,导师说这个算法很简单的,你怎么会不会?然后听完老师的讲解,豁然开朗,突然感觉对其进行算法实现也不是问题了。

目录

《数据结构与算法》——图的最小生成树之普利姆算法(Prime)总结

 

定义

伪代码实现

性能分析及应用

性能分析

应用

参考文献


定义

什么是Prime算法?它的核心思想是什么?

 

在此,我要引入一个小故事,一个在Dijkstra算法中引用过的小例子。

在一片广袤无垠的大海上,一艘名为泰坦尼克号的游轮在航行,而你恰巧就在这船上,很不幸船突然撞倒了冰山上,所有的人都在逃生。幸运的是,你现在跳到了一艘救生艇上,现在救生艇下面漂着100个人,你和这100个人之间或多或少的都有些联系,救生艇能将你们所有人救出来,但救生艇每次只能上一个人,在忽略人员性别等问题,单纯从和你相关关系的角度出发的情况下,请问怎么救人?

在题目中“你”是一个只看私人感情的人,毋庸置疑,得先救出和自己关系最好的人小A,然后救生艇上就变成了你们两个再管理了,下一个救谁?通过商量决定救起下一个和俩人关系相对较好的人,即从{自己与水中人的关系,小A与水中人的关系}中进行比较选出最好关系对,于是你们救起了小B,此时变成了你们三个人一起管理救生艇,类似的从{自己与水中人的关系,小A与水中人的关系,小B与水中人的关系}中进行比较选出最好的关系对,并由其救起小C,以此类推,直至将所有落水者救出为止。(注:本例子只用作辅助理解,并无其他意思。)

在救人的过程中,我们需要两个名单作为记录,一个用于记录各个落水者与“你(们)”的关系程度,一个用于记录救起各个落水者的人员。

 

        即核心思想为:存在两个集合一个空集U和一个满集A,首先从A中取出一个元素作为起始点添加入U中,从A中寻找和集合U中所有点最近的一个点添加入集合U中,记录导致该点加入U的关系边,直至将A中所有的点添加入U中,最终得到的所有的关系边所构成的树型结构即为最小生成树。

 

用算法的语言来描述如下:

arcs[][]:记录各个顶点到其它顶点的直接长度。(包括“你”在内的各个落水者的直接关系)

path[]:记录源点到各个节点的最短路径的前驱节点(救起各个落水者的人员),初始值为arcs[v0][i](和“你”的关系)。

lowcost[]:记录源点到各个节点的最短路径长度。(关系)

 

假设从v0出发,初始化:U={v0},lowcost [i]=arcs[v0][i],path[i] = v0,i为集合v剩余节点,v=v-s(在集合v中去掉初始点)

while(v集合不为空){

从集合v中选出一个顶点vj,它满足Min{ lowcost [vi]其中,vi属于v},此点即为此时到集合U的一条最短路径的终点U = U +{vj}  v=v-{vj}

修改lowcost[vj] = Min{ lowcost [vj],arcs[vi][ vj]},若lowcost发生变化,则path[vj] = vi

输出所有的<i,path[i]>所构成的树形结构即为所求。

 

伪代码实现

/*****************************
Description: 图的最小生成树之普利姆算法(Prime)
******************************/
#define MAX_VERTEX_NUM 100 
void MiniTree_Prime(Graph G,VertexType u){
	//使用Prime算法进行最小生成树的构造
	//参数为一个图形结构,和一个结点u
	//用lowcost[]的值来区分属于哪个集合,最终状态应该为全0 
	int path[MAX_VERTEX_NUM];
	int lowcost[MAX_VERTEX_NUM];
	int k =LocateNode(G,u); //获取u点的下标 
	for(int i = 0;i<G.vexnum;i++){//对辅助数据进行初始化 
		if(i^k){
			path[i] = k;
			lowcost[i] = G.arcs[k][i].adj;
		}
	}//for
	lowcost[k] = 0; 
	for(int i = 0;i<G.vexnum-1;i++){//对剩余n-1个点进行查找添加 
		k = getMinVex(lowcost);//获取此时是距离最近的点 
		locost[k] = 0 ;//添加当前点 
		printfAdj(path[k],k);//输出当前边 
		for(int j = 0;j<G.vexnum;j++)//修改lowcost的值 
			if(j^k&&locost[j]>G.arcs[k][j].adj){
				path[j] = k;
				lowcost[j] = G.arcs[k][j].adj;
			}//if
	}//for
} //MiniTree_Prime

性能分析及应用

性能分析

空间复杂度:

借用了两个长为|v|的数组用来保存最小代价和路径前驱点,故空间复杂度为o(|V|)。

 

时间复杂度:

通过算法思想我们不难发现,我们需要移动n个点而每次移动完一个点后都需要更改一次lowcost的值,所以需要n*n的时间规模,所以时间复杂度为o(|V|^2),emmmmmm,和边多少没有丁点儿关系,所以我们可以用来解决边很多很多的图(稠密图)。

应用

情绪到位了,咱啥也不管了,也不藏着掖着了,本来想以普通学渣的身份和题目相处,可换来的却是疏远,行了我不装了,我摊牌了,下面这道题是某校某年的真题!

 

题目大意:当前农村公路建设正如火如荼的展开,某乡镇政府决定实现村村通公路,工程师现有各个村落之间的原始道路统计数据表,表中列出了各村之间可以建设公路的若干条道路的成本,你的任务是根据给出的数据表,求使得每个村都有公路连通所需要的最低成本。

 

分析:对题目进行抽象化处理v个村(点),各个村之间的所有公路(边),成本(权值),最低成本即为最小加权路径长度,即求最小生成树。

解:

算法思想:通过使用prime算法求出最小生成树。

变量说明:path[]存储当前最小生成树中与其连接的上一个点

lowcost[]存储当前建造工路即加入生成树时的最小代价

图型结构G用来存储各个村落之间的关系,G.arcs[i][j]存储第i个村到第j个村的公路代价

#define MAX_VERTEX_NUM 100 
void MiniTree_Prime(Graph G,VertexType u){
	k = locateAdj(G,u);//定位u点在图中的编号
	int lowcost[MAX_VERTEX_NUM]; 
	int path[MAX_VERTEX_NUM];
	for(int i = 0; i<G.vexnum; i++)//辅助数组的初始化
	if(i^k){
		lowcost[i] = G.arcs[k][i].adj; 
		path[i] = k;
	}
	path[k] = k;
	for(int i = 0 ; i<G.vexnum-1; i++){
		k = getMinVex(lowcost);//获取当前距离生成树最近的结点 
		lowcost[k] = 0;//加入树中
		printfEdge(k,path[k]);//输出当前边 
		for(int j = 0 ; j<G.vexnum; j++)//修改lowcost的值 
			if(j^k&&lowcost[j]>G.arcs[k][j].adj){
				lowcost[j] = G.arcs[k][j].adj; 
				path[j] = k;
			}
	}
}//MiniTree_Prime

参考文献

严蔚敏,吴伟民. 数据结构(C语言版)[M]. 北京: 清华大学出版社,2013.

 

如有错误,还请朋友不吝指正。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值