数据结构——普里姆(Prim)算法

这篇具有很好参考价值的文章主要介绍了数据结构——普里姆(Prim)算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。
以下是数据结构中关于普里姆算法的操作(编程风格参考严蔚敏版数据结构)。

头文件及宏

#include<iostream>
#include<stdio.h>
using namespace std; 
typedef char VerTexType; 
typedef int ArcType; 
#define MaxInt 32767 
#define MVNum 100    
#define OK 1
#define ERROR -1;
typedef int status;

图以及最短边集合的声明

typedef struct{
	VerTexType vexs[MVNum] {'A','B','C','D','E','F'};
	ArcType arcs[MVNum][MVNum];
	int vexnum = 6,arcnum = 10;
}AMGraph; 

typedef struct{
	VerTexType adjvex;//最小边在顶点集U的顶点 
	ArcType lowcost;//最小边上的权值 
}Closedge[MVNum];

特别说明!!!!!
在Closedge中,起点是通过节点VerTexType类型变量表示,而终点是通过下标int类型变量来表示。
adjvex就是某条边的起点,lowcost就是两点之间权值(距离),closedge[i]里的i是终点的下标。
理解好这个很重要,如果这个理解不好,那就不知道Prim里close辅助数组是怎么用的了。

举个例子

数据结构——普里姆(Prim)算法
如何算出上图里的最小生成树呢?
老样子先弄出邻接矩阵:
数据结构——普里姆(Prim)算法

Prim核心算法:

void Prim(AMGraph &G,VerTexType v){
	int vi = LocateVex(G,v);//获取起始点的下标
	Closedge close;//辅助数组,用来记录不同点之间的距离以及起始位置(可理解为是一个点边集合) 
	for(int i=0;i<G.vexnum;i++){
		if(vi!=i){
			close[i].adjvex=v;
			close[i].lowcost=G.arcs[vi][i];//初始化辅助数组close,让起点直连其它节点(就是假设起点到全部点的距离都是最短) 
		}else{
			close[i].lowcost = 0;
		} 
	} 
	for(int i=1;i<G.vexnum;i++){//i从1开始是因为循环不需要执行vexnum次,不必管节点到自己的距离 
		int k = Min(close,G);//获取当前点边集合里边权值最小的终点(close里下标表示终点,adjvex表示起点,lowcost表示权值) 
		VerTexType start = close[k].adjvex;//当前边集合里最短边的起点
		VerTexType end = G.vexs[k];//当前边集合里最短边的终点
		cout<<start<<"-"<<close[k].lowcost<<"-"<<end<<endl;//输出本次找出来的最短边及端点
		for(int j=0;j<G.vexnum;j++){//更新close表 
			if(G.arcs[k][j]<close[j].lowcost){//如果end到j点的距离小于start到j点的距离 
				//这是以对象的形式简写 
				close[j] = {G.vexs[k],G.arcs[k][j]};//最短距离从start到j点距离修改成end到j点的距离 
				//等价于这样写
//				close[i].adjvex=G.vexs[k]; 
//				close[i].lowcost=G.arcs[k][j];
			}//if
		}//for 
	} 
}

算法执行过程(红色线表示更新的边,蓝色的表示已被选取的边,黑色的表示当前步骤未被操作的边):

初始化辅助数组close。这一步目的是让起点直连其它的节点(就是说假设起点到其它全部节点的距离是最短的)。画出来是这样的: 数据结构——普里姆(Prim)算法
此时的close记录的就是从A到其它全部节点的距离的集合。
开始第一轮循环:在close这些边里选出最短的边,AC的值最小,记录起点为A终点为C(不必做更新操作,因为这条边本就在close里)。然后以AC同时和BEFD比较距离(权值大小)。比如:A到B的距离为为6,C到B的距离是5,close里本来是A到B的边变成C到B,然后close变成如下情况:
数据结构——普里姆(Prim)算法

然后AC和E比较,和F比较、和D比较,CE<AE,CF<AF。得出来的close就是这样:
数据结构——普里姆(Prim)算法
第二轮循环开始:然后选出最短的那条:CF(权值为4)。此时close是这个情况:
数据结构——普里姆(Prim)算法

然后A、C、F同时比较距离和B、E、D的距离。CB权值最小close不变,C和F到E距离一致,保持CE相连,FD权值比CD和AD都小,连接FD,更新close。此时的close是这样子的:
数据结构——普里姆(Prim)算法
第三轮循环开始:此时的close是这样的:
数据结构——普里姆(Prim)算法
A、C、F、D同时和B、E比较距离:发现是CB最短(但是在2轮循环里CB这条边已经在close里了,就没有实际更新close的操作)
第四轮循环开始:此时的close是这样的:
数据结构——普里姆(Prim)算法
A、B、C、D、F同时与E比较权值:BE的距离比原先的CE短,取消CE更新为BE。此时的close是这个情况:
数据结构——普里姆(Prim)算法
此时最小生成树生成完毕。最后结果如下所示:
数据结构——普里姆(Prim)算法

代码执行结果:

数据结构——普里姆(Prim)算法

源码

#include<iostream>
#include<stdio.h>
using namespace std; 
typedef char VerTexType; 
typedef int ArcType; 
#define MaxInt 32767 
#define MVNum 100    
#define OK 1
#define ERROR -1;
typedef int status;

typedef struct{
	VerTexType vexs[MVNum] {'A','B','C','D','E','F'};
	ArcType arcs[MVNum][MVNum];
	int vexnum = 6,arcnum = 10;
}AMGraph; 

typedef struct{
	VerTexType adjvex;//最小边在顶点集U的顶点 
	ArcType lowcost;//最小边上的权值 
}Closedge[MVNum];
//其实说白了就是adjvex就是某条边的起点,lowcost就是权值(距离),closedge[i]的i是终点。
//理解好这个很重要。 
status CreateUDN(AMGraph &G){//创建无向图 	
	for(int i=0;i<G.vexnum;i++){
		for(int j=0;j<G.vexnum;j++){
			if(i==j){
				G.arcs[i][j] = 0;
			}else
				G.arcs[i][j] = MaxInt;//初始状态全部节点之间相互不可达
		}
	}
	G.arcs[0][1]=6;G.arcs[0][2]=1;G.arcs[0][3]=5;
	G.arcs[1][2]=5;G.arcs[1][4]=3;
	G.arcs[2][3]=5;G.arcs[2][4]=6;G.arcs[2][5]=4;
	G.arcs[3][5]=2;
	G.arcs[4][5]=6;
	for(int i=0;i<G.vexnum;i++){
		for(int j=0;j<G.vexnum;j++){
			if(G.arcs[i][j]!=MaxInt){
				G.arcs[j][i] = G.arcs[i][j];
			} 
		}
	}//矩阵对称 
	return OK; 
}

void ShowGraph(AMGraph G){
	cout<<" ";
	for(int i=0;i<G.vexnum;i++){
		cout<<" "<<G.vexs[i];
	}
	cout<<endl;
	for(int i=0;i<G.vexnum;i++){
		cout<<G.vexs[i]<<" ";
		for(int j=0;j<G.vexnum;j++){
			if(G.arcs[i][j]==MaxInt){
				cout<<"* ";
			}else{
				cout<<G.arcs[i][j]<<" ";
			}
		}
		cout<<endl;
	}
}

int LocateVex(AMGraph G, VerTexType v){
	int i;
	for(i=0;i<G.vexnum;i++){
		if(G.vexs[i]==v){
			return i;
		}
	} 
	return ERROR;
}

int Min(Closedge close,AMGraph G){
	int min = MaxInt;
	int mini;
	for(int i=0;i<G.vexnum;i++){
		if(min>close[i].lowcost&&close[i].lowcost!=0){//不等于0是指不和自身比较,没意义 
			min = close[i].lowcost;
			mini = i; 
		}
	}
//	cout<<mini<<endl;
	return mini;
} 

void Prim(AMGraph &G,VerTexType v){
	int vi = LocateVex(G,v);//获取起始点的下标
	Closedge close;//辅助数组,用来记录不同点之间的距离以及起始位置(可理解为是一个点边集合) 
	for(int i=0;i<G.vexnum;i++){
		if(vi!=i){
			close[i].adjvex=v;
			close[i].lowcost=G.arcs[vi][i];//初始化辅助数组close,让起点直连其它节点(就是假设起点到全部点的距离都是最短) 
		}else{
			close[i].lowcost = 0;//0表示自身或该边已被选取。 
		} 
	} 
	for(int i=1;i<G.vexnum;i++){//i从1开始是因为循环不需要执行vexnum次,不必管节点到自己的距离 
		int k = Min(close,G);//获取当前点边集合里边权值最小的终点(close里下标表示终点,adjvex表示起点,lowcost表示权值) 
		VerTexType start = close[k].adjvex;//当前边集合里最短边的起点
		VerTexType end = G.vexs[k];//当前边集合里最短边的终点
		cout<<start<<"-"<<close[k].lowcost<<"-"<<end<<endl;//输出本次找出来的最短边及端点
		for(int j=0;j<G.vexnum;j++){//更新close表 
			if(G.arcs[k][j]<close[j].lowcost){//如果end到j点的距离小于start到j点的距离 
				//这是以对象的形式简写 
				close[j] = {G.vexs[k],G.arcs[k][j]};//最短距离从start到j点距离修改成end到j点的距离 
				//等价于这样写
//				close[i].adjvex=G.vexs[k]; 
//				close[i].lowcost=G.arcs[k][j];
			}//if
		}//for 
	} 
}

int main(){
	AMGraph G;
	CreateUDN(G);
	ShowGraph(G);
	Prim(G,'A'); 
	return 0;
}

关于时间复杂度和空间复杂度

设顶点数n,边数e。邻接矩阵:O(n^2) 邻接表:O(elogn)

敬请批评指正。文章来源地址https://www.toymoban.com/news/detail-461489.html

到了这里,关于数据结构——普里姆(Prim)算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • prim算法(普里姆算法)详解

    了解了什么是最小生成树后,本节为您讲解如何用普里姆(prim)算法查找连通网(带权的连通图)中的最小生成树。 普里姆算法查找最小生成树的过程,采用了贪心算法的思想。对于包含 N 个顶点的连通网,普里姆算法每次从连通网中找出一个权值最小的边,这样的操作重

    2024年01月16日
    浏览(26)
  • 数据结构---最小生成树((普里姆算法)C语言看了就懂教程)

        普里姆算法就是“加点法”,是一种将连通网转换成最小生成树的一种算法     在一个连通图的所有生成树中,各边代价之和最小的那颗生成树称为该连通图的最小代价生成树(MST)     ①对于任意一张连通图,假设 N = (V,E)是连通网,TE就是最小生成树中边的集合    

    2024年02月03日
    浏览(28)
  • 求最小生成树Prim(普里姆)和Kruskal(克鲁斯卡尔)算法

     想求最小生成树,我们首先得弄懂以下几个概念   连通图 :图中任意两个顶点都是连通的 极小连通子图 :既要保持图连通又要使得边数最少的子图 生成树 : 包含图中全部顶点的一个极小连通子图 连通图用通俗的话来讲就是,某一个顶点,可以 直接或者间接 (通过其他顶点

    2024年02月05日
    浏览(32)
  • 最小生成树(详解普里姆算法)

    首先,我们来看一下 图的一些基本知识点 : 图 :图 G=(V,E) 由顶点集 V 和边集 E 组成。每条边对应一个点对 (v,w),其中 v,w 属于 V 。如果图中的点对是有序的,那么该图就是有向图,反之为无向图。 邻接点 :若顶点 v 与 w 之间存在一条边,则认为顶点 v 与 w 邻接。 权 :图

    2024年01月19日
    浏览(69)
  • 已知无向图G如下所示,使用普里姆 (Prim)算法求图G的最小生成树。 (a)请写出从顶点T出发,加到最小生成树中的边次序。 (6分) (2)说明Prim算法更适用于求哪种类型无向图的最小生 成树。(2分) (3)当图中顶点个数为n,边的个数为e时,该算法

    (a)从顶点T出发,加到最小生成树中的边次序如下: 先加入顶点T到顶点E的边,得到的最小生成树为:T-E 再加入顶点E到顶点D的边,得到的最小生成树为:T-E-D 再加入顶点D到顶点B的边,得到的最小生成树为:T-E-D-B 再加入顶点B到顶点C的边,得到的最小生成树为:T-E-D-B-C 再加

    2024年01月17日
    浏览(31)
  • (数据结构)普利姆算法(Prim)实现

    假设要在n个城市之间建立通信联络网,每两个城市之间建立线路都需要花费不同大小的经费,则连通n个城市只需要n-1个条线路,最小生成树解决的问题就是: 如何在最节省经费的前提下建立这个通信网 也可以理解为:n个城市之间最多可以建立n(n-1)/2条线路,我们要从这里挑

    2024年02月03日
    浏览(33)
  • 数据结构作业—第十三周---- Prim算法 Kruskal算法 Dijkstra算法

    (只看点,不看边,适合边较多的图,即 稠密图 )       是一种按权值的递增次序选择合适的边来构造最小生成树的方法;( 稀疏图 ) 适合带权有向图和带权无向图求单源最短路径; 不适合含负取值的图,求最短路径; 1 . 单选题 简单 7分 对于有n个顶点的带权连通图

    2024年02月15日
    浏览(37)
  • 0302Prim算法-最小生成树-图-数据结构和算法(Java)

    1.1 概述 1.1.1 算法描述 算法描述: 初始化最小生成树,只有一个起点; 每次将下一条连接树中顶点和其补集中顶点且权重最小的边(黑色表示)加入树中; 重复步骤中2,直至最小生成树中加入了V-1条边。 命题L。Prim算法能够得到任意加权连通图的最小生成树。 证明:有命

    2023年04月16日
    浏览(31)
  • C++数据结构——习题6-5 最小生成树(Prim算法)

    省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。已知村庄数N和可建道路数M,设初始状态下任意村庄之间没有路,请编写程序,根据输入的两村庄间修建道路的费用情况,计算这些村庄

    2024年02月09日
    浏览(67)
  • 算法 数据结构分类 数据结构类型介绍 数据结构线性非线性结构 算法合集 (一)

     数据结构分为:                            a.线性结构                            b.非线性结构  a.线性结构:                       数据与结构存在一对一的线性关系; a . 线性结构 存储 分为:                                   顺序存储

    2024年02月10日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包