最小生成树普里姆算法Prim
目录
前言
一、Prim算法的基本思路
二、代码实现
总结
前言
无论是什么程序都要和数据打交道,一个好的程序员会选择更优的数据结构来更好的解决问题,因此数据结构的重要性不言而喻。数据结构的学习本质上是让我们能见到很多前辈在解决一些要求时间和空间的难点问题上设计出的一系列解决方法,我们可以在今后借鉴这些方法,也可以根据这些方法在遇到具体的新问题时提出自己的解决方法。(所以各种定义等字眼就不用过度深究啦,每个人的表达方式不一样而已),在此以下的所有代码都是仅供参考,并不是唯一的答案,只要逻辑上能行的通,写出来的代码能达到相同的结果,并且在复杂度上差不多,就行了。
一、Prim算法的基本思路
Prim算法就要比Kruskal要简单很多,总的来说Prim算法就是将顶点分为两类:一类是在查找中就包含在生成树中的顶点,而剩下的就是另一类。
具体是什么意思呢,我们以这个带权图为例:
根据上文红字的描述,首先我们要先创建出两个类A、B,当然这里不是C++中的类,而是在逻辑上的一种抽象的概念;如下图所示:
在一开始图中所有的节点都在B类中,现在我们要找任意一个节点作为起始点放入A类中,然后持续地去找该节点的所有相邻点中权值最小的节点放入A类。
假定我们选择V0节点作为起始节点,①把V0放进A类中;②再找V0相邻的所有权值最小的点放进A类中,
从带权图中我们可以得到与V0相邻的节点有V1和V5,而它们之间的边的权值分别是3和4,毫无疑问V1就是我们这一步要找的节点;
①
②
第③步,接着再找V0和V1所有相邻的点有V2 V8 V5 V6,同理可以得出V5为顶点的边权值最小,所以把V5放进A类中;
第④步再找V0 V1 V5所有相邻的点有V2 V8 V6 V4,V8是最小权值的边的顶点,放入V8;
第⑤步再找V0 V1 V5 V8的所有邻接点V2 V3 V6 V4,同理放入V2;
第⑥步找V0 V1 V5 V8 V2的所有邻接点V3 V6 V4,放入V6;
第⑦步重复上述的操作,先后放入V7 V4 V3。
③
④
⑤
⑥
⑦
至此,所有的节点都放进了A类当中,回顾上述的这些操作,根据放入A类的节点的先后顺序,我在带权图上也标记了相对应的边,如下图所示,这些顶点和边就是我们要找的一个最小生成树;
把红色的部分单独拿出来,就是我们要找的其中一个最小生成树;
二、代码实现
理清了逻辑接下来就是代码实现。Prim在代码实现上相比于Kruskal来说也很简单,只需要按照上文的逻辑模拟就行了。
这里我还是用邻接矩阵去构建这么一个带权图,因为需要不断去访问边的权值;
void creategrahp(AdjMatrix* G)
{int n, e;//n代表顶点数 e代表边数int vi, vj;//vi vj代表边的两个顶点对int w;//表示边的权值printf("要输入的顶点数和边数\n");scanf("%d%d",&n,&e);G->numV = n; G->numE = e;//图的初始化for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){if(i == j){//一个非带权的图 0代表没有边 1代表有边//边不指向自己 即对角线为0G->Arc[i][j] = 0;}else{//如果是带权的图 初始化为0或者为一个不可能的值G->Arc[i][j] = 65535;}}}//将顶点存入数组for(int i = 0; i < G->numV; i++){printf("请输入第%d个节点的信息\n",i + 1);scanf("%d", &G->Vertices[i]);}//输入边的信息for(int i = 0; i< G->numE; i++){//如果输入的是顶点的值 需要从顶点集中查找对应的下标 //如果是带权图 还要输入权的信息printf("请输入边的信息Vi,Vj和权值w\n");scanf("%d%d%d",&vi,&vj,&w);G->Arc[vi][vj] = w;//如果是带权图 等于权值//如果是有向图 就不对称//如果是无向图 矩阵对称G->Arc[vj][vi] = w;}
}
构建完的矩阵如下图所示(因为是无向图所以另一半只需要沿对角线镜像一下就行了,我比较懒,这里就不画全了)
接下来我们开辟两个数组adjvex和lowcast;其中adjvex是表示用来保存相关节点的下标的,也就是我们在上文中提到的A类;lowcast用来保存相关边的权值;这里我们仍用V0为例:开始节点为V0,那么在应该在lowcast数组中存入所有与V0有关的边的权值,如果不存在边就用inf表示;
并且在adjvex数组中,第 i 号元素的下标对应的值表示该节点连接的另一个节点(一条边的起始节点)所以应该把adjvex中的所有元素赋值为0(表示该点与V0连接)
void Prim(AdjMatrix* G)
{int adjvex[MAXVEX];//用来保存相关节点的下标int lowcast[MAXVEX];//用来保存相关边的权值lowcast[0] = 0;//初始化第一个权值为0 表示v0加入最小生成树adjvex[0] = 0;//第一个顶点下标为0for(int i = 1; i <= G->numV; i++)//循环除了0以外的全部顶点{//将与v0有关的边的权值全部存入数组lowcast[i] = G->Arc[0][i];adjvex[i] = 0;}
接下来就是要去找权值最小的边,并记录这条边的结束节点K,边(V0,Vk)就是最小生成树的一条边,所以把k放进生成树中,并做上标记表示已经访问过该节点;
//找寻最小权值for(int i = 1; i < G->numV; i++){int min = INFINTIY;int k = 0;//返回最小值的下标int j = 1;for(; j <= G->numV; j++)//Vj是除V0以外的顶点{//如果Vi和Vj有边或这条边没有被找到,且边的权值最小if(lowcast[j] != 0 && lowcast[j] < min){min = lowcast[j];//就让当前权值成为最小值k = j;}}//打印当前找到的顶点的边中 权值最小的边printf("(%d %d)--%d ", adjvex[k], k, lowcast[k]);//将当前顶点的权值设置为0 代表加入了生成树中lowcast[k] = 0;
回顾上文的步骤,接下来我们要找的是V0节点和Vk节点的所有邻接点,继续找权值最小的边,所以我们应该更新lowcast和adjvex数组,把与Vk有关的边(之前没被访问过的)的权值放进lowcast中,并把这个边的另一个节点Vj在adjvex中所对应的下标的值改为k;
重复上述步骤,直到所有点都加入了。
for(j = 1; j <= G->numV; j++){//如果下标为k的顶点相邻的各边的权值小于此前未被加入的顶点的权值 则加入生成树中if(lowcast[j] != 0 && G->Arc[j][k] < lowcast[j]){//更新lowcast和adjvex数组lowcast[j] = G->Arc[j][k];adjvex[j] = k;}}
至此Prim算法写完了。
总结
最小生成树应用场景
城市铺路
网络铺设
面部识别
源码
#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 200
#define INFINTIY 65535
//prim算法
//邻接矩阵
typedef struct AdjacentMatrix
{//顶点集int Vertices[MAXVEX];//边集int Arc[MAXVEX][MAXVEX];//顶点数 边数int numV, numE;
}AdjMatrix;
//用带权无向邻接矩阵生成图void creategrahp(AdjMatrix* G)
{int n, e;//n代表顶点数 e代表边数int vi, vj;//vi vj代表边的两个顶点对int w;//表示边的权值printf("要输入的顶点数和边数\n");scanf("%d%d",&n,&e);G->numV = n; G->numE = e;//图的初始化for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){if(i == j){//一个非带权的图 0代表没有边 1代表有边//边不指向自己 即对角线为0G->Arc[i][j] = 0;}else{//如果是带权的图 初始化为0或者为一个不可能的值G->Arc[i][j] = 65535;}}}//将顶点存入数组for(int i = 0; i < G->numV; i++){printf("请输入第%d个节点的信息\n",i + 1);scanf("%d", &G->Vertices[i]);}//输入边的信息for(int i = 0; i< G->numE; i++){//如果输入的是顶点的值 需要从顶点集中查找对应的下标 //如果是带权图 还要输入权的信息printf("请输入边的信息Vi,Vj和权值w\n");scanf("%d%d%d",&vi,&vj,&w);G->Arc[vi][vj] = w;//如果是带权图 等于权值//如果是有向图 就不对称//如果是无向图 矩阵对称G->Arc[vj][vi] = w;}
}void Prim(AdjMatrix* G)
{int adjvex[MAXVEX];//用来保存相关节点的下标int lowcast[MAXVEX];//用来保存相关边的权值lowcast[0] = 0;//初始化第一个权值为0 表示v0加入最小生成树adjvex[0] = 0;//第一个顶点下标为0for(int i = 1; i <= G->numV; i++)//循环除了0以外的全部顶点{//将与v0有关的边的权值全部存入数组lowcast[i] = G->Arc[0][i];adjvex[i] = 0;}//找寻最小权值for(int i = 1; i < G->numV; i++)//用来循环生成边的次数{int min = INFINTIY;int k = 0;//返回最小值的下标int j = 1;for(; j <= G->numV; j++)//Vj是除V0以外的顶点{//如果Vi和Vj有边或这条边没有被找到,且边的权值最小if(lowcast[j] != 0 && lowcast[j] < min){min = lowcast[j];//就让当前权值成为最小值k = j;}}//打印当前找到的顶点的边中 权值最小的边printf("(%d %d)--%d ", adjvex[k], k, lowcast[k]);//将当前顶点的权值设置为0 代表加入了生成树中lowcast[k] = 0;for(j = 1; j <= G->numV; j++)//从k之后节点开始,进入下一轮迭代{//如果下标为k的顶点相邻的各边的权值小于此前未被加入的顶点的权值 则加入生成树中if(lowcast[j] != 0 && G->Arc[j][k] < lowcast[j]){//更新lowcast和adjvex数组lowcast[j] = G->Arc[j][k];adjvex[j] = k;}}}
}int main()
{AdjMatrix G;creategrahp(&G);Prim(&G);system("pause");return 0;
}
最小生成树普里姆算法Prim相关推荐
- (数据结构)图的最小生成树 普里姆算法(Prim)
假设要在n个城市之间建立通信联络网,每两个城市之间建立线路都需要花费不同大小的经费,则连通n个城市只需要n-1个条线路,最小生成树解决的问题就是:如何在最节省经费的前提下建立这个通信网 也可以理解为: ...
- 普里姆算法(Prim)和克鲁斯卡尔(Kruskal)算法
普里姆算法(Prim)和克鲁斯卡尔(Kruskal)算法 普里姆算法的基本思想: 取图中任意一个顶点 v 作为生成树的根,之后往生成树上添加新的顶点 w.添加顶点w的条件为:w 和已在生成树上的顶点v ...
- 最小生成树(普里姆算法【Prim】与克鲁斯卡尔算法【Kruskal】)
写在前面:博主是一位普普通通的19届双非软工在读生,平时最大的爱好就是听听歌,逛逛B站.博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的事,做自己不后悔的事 ...
- Java用普里姆算法(prim)解决修路最短路径问题
14.6 普里姆算法 14.6.1 应用场景-修路问题 看一个应用场景和问题: 有胜利乡有 7 个村庄(A, B, C, D, E, F, G) ,现在需要修路把 7 个村庄连通 各个村庄的距离用边线 ...
- 最小生成树普里姆算法c语言代码,普里姆算法生成最小生成树-C语言描述.doc
PAGE JIN JINGCHU UNIVERSITY OF TECHNOLOGY <数据结构(C语言描述)> 课程设计 学 院 计算机工程学院 班 级 12级软件技术1班 学 号 201 ...
- 最小生成树——普里姆算法和克鲁斯卡尔算法
最小生成树 用来解决工程中的代价问题. 一:普里姆算法 具体代码用C语言实现如下: typedef int VRType;typedef char InfoType;#define MAX_NAME ...
- 【算法】普里姆算法 Prim算法解决修路问题
文章目录 1. 概述 1.1 最小生成树 2.普里姆算法介绍 3.代码 3.1 案例1 1. 概述 视频:https://www.bilibili.com/video/BV1E4411H73v?p=1 ...
- 最小生成树 普里姆算法
题目来源 POJ2349 在介绍什么是最小生成树之前先介绍什么是加权图 在之前已经默认了解了无向图(并查集)以及有向无环图(拓扑排序),那么最小生成树可以理解是一个加权的无向图,那么我们要坐的就是在 ...
- 学懂最小生成树(普里姆算法)
最小生成树,初学者可能会学的感觉云里雾里,不要怕,小编带大家搞懂它! 目录 一.概念介绍 二.实现原理 三.代码实现 一.概念介绍 最小生成树就是在一个图中找到能过一次性穿过所有顶点的最小路径. 上图 ...
最新文章
- 第八章 泛型程序设计
- Spring知识点提炼
- 【solr5.5环境搭建】在tomcat8里面部署solr5.5
- Qt Creator管理会议
- 批处理中setlocal enabledelayedexpansion的作用详细整理
- .NET CORE 怎么样从控制台中读取输入流
- [XSY]Illyasviel的图游戏(博弈论)
- python函数名与变量名可以一样吗_python--第一类对象,函数名,变量名
- 城市轨道交通运营票务管理论文_城市轨道交通运营企业的票务组织管理
- 开源软件运动为什么流行起来?
- python 常用函数用法
- 直播app源代码,单例模式
- jeesit的简单使用(四)
- 2021级南航计算机专硕829备考记录
- windows系统安装wget指令
- c语言自动按键脚本,纯C语言写的按键驱动,将按键逻辑与按键处理事件分离~
- C语言使用文件指针时遇到的位置问题
- BigData:根据最新2018.07.19《财富》世界500强榜单进行大数据分析
- STM32芯片无法下载 芯片锁死 M3错误的一种解决方案
- 【雅思口语】安娜口语学习记录 Part2