当我们想要找连通网的最小生成树时,经典的有两种算法,普里姆算法和克鲁斯卡尔算法,这里我们介绍的便是普里姆算法.

普里姆算法流程:

ps:上图来自于大话数据结构

1.假设我们找顶点V0作为首个遍历的顶点(也就是最小生成树的第一个结点),我们观察与V0相连接的顶点有V1和V5,而与V1相连的权值为10,与V5相连的权值为11,所以我们选取权值小的也就是V1作为我们最小生成树的第二个结点。

2.此时我们继续观察与V0,V1相连的顶点有V2,V5.V6,V8,其中这几个顶点与V0,V1之间的权值为:18,11,16,12其中最小的权值是V0与V5顶点之间的权值11,则我们最小生成树的第三个顶点是V5.

3.接下来我们观察已经获得的顶点V0,V1,V5,与V0,V1,V5相连的顶点有V2,V4,V6,V8,他们与顶点V0,V1,V5之间的权值为18,26,16,12,其中最小的权值是V1与V8之间的12,则我们最小生成树的第四个顶点是V8.

...............

接下来的操作想必不用我多说了,继续按照上面的方法找到合适的路径将所有结点都放入最小生成树,我们便找到了遍历完该图所有顶点的最短路径。

ps:画图一起走比较好理解哦

所以根据以上我们遍历图的操作,我们可以知道我们在编程普里姆(Prim)算法的代码时需要注意的两个点:

1.我们在寻找最短路径时不只是找距离一个顶点的最短路径,而是与此时已经在最小生成树中的顶点有关系的所有路径中的最短路径。(比如我们在找到V1后找下一个最短路径,找的就不只是与V1相关的路径中的最短路径,而是找与V0,V1相关的路径中的最短路径)

2.我们在程序中遍历找到最短路径的尾顶点后,如何知道路径的首顶点是谁。

当然大佬已经帮我们解决了这些麻烦的问题,大佬通过创建了两个辅助数组来解决了这两个问题,一个数组用来储存顶点的下标,这个数组就是adjvex【】,这个数组的下标表示在最小生成树中的顶点,而对应储存的数据是该顶点的双亲(比如adjvex【1】=0表示顶点V1在最小生成树中的双亲是顶点V0,也就说明在图中路径(V0,V1)是一条最短路径)一开始我们可以将adjvex【】数组的值都初始化为0,因为一开始就只有顶点V0在最小生成树中,所以每个顶点的双亲都有可能是V0。

第二个数组用于储存顶点间的权值,这个数组就是lowcost【】,这个数组可以理解为储存连接顶点的边(比如lowcost【1】=10表示此次的遍历连接顶点V1的路径的权值是10),一开始我们将顶点V0与所有顶点之间的权值都存入(注意当我们已经确认了一个顶点Vi放入最小生成树,对应的lowcost【i】应该变为0,此时lowcost【i】的值不在会改变,所以我们的顶点V0已经放入最小生成树了因此初始化时应该将lowcost【0】=0)

ps:要是两个顶点间没有权值则设为INFINITY表示无穷

1.此时数组lowcost【】初始化为

{0,10,INFINITY,INFINITY,INFINITY,11,INFINITY,INFINITY,INFINITY}

我们遍历该数组找其中除0以外最小的值是lowcost【1】=10,则此时我们就确认了一条连接顶点V1的最短路径的权值是10,这时我们怎么知道在最小生成树中连接V1的顶点是谁呢,adjvex数组的作用就体现出来了此时adjvex【1】=0,所以我们知道顶点V1在最小生成树中的双亲应该是V0,于是我们得到了边(V0,V1)应该是第一条最短路径。注意我们在找到顶点V1以后要将lowcost【1】=0,使其之后的遍历不再改变,毕竟连接顶点的只有一条边吗,双亲也只有一个。此时lowcost数组为{0,0,INFINITY,INFINITY,INFINITY,11INFINITY,INFINITY,INFINITY}

接下来我们需要找到与顶点V0,V1有关的最短路径,怎么实现呢,我们可以找到顶点V1与其他邻接点的路径,即{10,INFINITY,18,INFINITY,INFINITY,INFINITY,16,INFINITY,12},此时的lowcost数组{0,0,INFINITY,INFINITY,INFINITY,11,INFINITY,INFINITY,INFINITY},除了lowcost数组中为0的位置,其他位置都进行比较,取最小的存入lowcost数组,最后我们得到lowcost数组为:{0,0,18,INFINITY,INFINITY,11,16,INFINITY,12}

并且lowcost数组发生改变的位置adjvex数组也应该改变,比如此时lowcost【2】改为了18,表示里面存入的路径是(V1,V2),说明该次遍历中顶点V2的双亲是V1,则改adjvex【2】=1,之后也同样adjvex【6】=1,adjvex【8】=1。此时lowcost数组中储存的数据便是距离顶点V0,V1的最小路径。

遍历lowcost数组得到除0以外的最小值是lowcost【5】=11,即我们找到了第个放入最小生成树的顶点V5,根据adjvex【5】=0,我们知道路径(V0,V5)是第二条最短路径,将lowcost【5】=0。接下来遍历出顶点V5与其他顶点的权值,再与lowcost数组中除0以外的值进行比较并保留较小的值,与上面的操作就是循环了就不讲了。

激动的代码展示:

注意看MinBiTree_Prim函数即可

关于无向网图的创建的创建看这里:邻接矩阵

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
typedef char VertexType;//顶点类型
typedef int EdgeType;//边上的权值类型
#define MAXVEX 100//最大顶点数(开辟储存顶点的一维数组的空间大小)
#define INFINITY 65535//用65535来代表无穷(在储存边的二维数组中,对没有该边存在的表格,权值设为无穷)
//定义图的结构体(图由储存顶点的一维数组和储存边的二维数组,以及记录图中结点数和边数的int类型的变量组成)
struct MGraph
{VertexType vexs[MAXVEX];//储存顶点的一维数组EdgeType arc[MAXVEX][MAXVEX];//储存边的二维数组int Num_vex, Num_arc;//图中的顶点数和边数
};
//无向网图的创建
void Create_MGraph(MGraph& G)
{int m, n;cout << "请输入图的顶点数和边数" << endl;cin >> G.Num_vex >> G.Num_arc;cout << "请依次输入图的顶点:" << endl;for (int i = 0; i < G.Num_vex; i++){cin >> G.vexs[i];}//初始化储存边的二维数组for (int i = 0; i < G.Num_vex; i++)for (int j = 0; j < G.Num_vex; j++){G.arc[i][j] = INFINITY;}//向二维数组中输入对应边的权值for (int k = 0; k < G.Num_arc; k++){cout << "请依次输入边(Vm,Vn)的下标m,n" << endl;cin >> m >> n;cout << "请输入边(" << m << "," << n << ")的权值" << endl;cin >> G.arc[m - 1][n - 1];//由于是无向网图,所以存在边(m,n),就存在边(n,m)所以我们还应该向二维数组的(n,m)位置输入权值G.arc[n - 1][m - 1] = G.arc[m - 1][n - 1];}
}//普里姆算法(prim)生成最小二叉树
void MinBiTree_Prim(MGraph& G)
{//储存顶点下标的数组//数组的下标表示对应顶点的下标,数组储存的是对应顶点的双亲//比如adjvex[1]=5,说明在生成的最小二叉树中位于顶点数组 vexs[1]位置的顶点的双亲是顶点数组vexs[5]位置的顶点int adjvex[MAXVEX];//储存权值的数组,如lowcost[1]=10表示此时连接顶点vexs[1]的边的最小权值为10,要是成功将顶点vexs[1]放入最小二叉树,则lowcost[1]设为0int lowcost[MAXVEX];//初始化数组//以vexs[0]的点作为起始点for (int i = 0; i < G.Num_vex; i++){adjvex[i] = 0;}for (int i = 0; i < G.Num_vex; i++){lowcost[i] = G.arc[0][i];}//顶点vexs[0]已经作为第一个顶点是根结点不需要找连接的边lowcost[0] = 0;//循环一次找出一个顶点到最小生成树中//由于顶点0已经设为第一个最小生成树中的顶点,所以i从0开始for (int i = 1; i < G.Num_vex; i++){int min = INFINITY;//用k表示此时所找到的放入二叉树的顶点vexs[k]int k = 0;for (int i = 1; i < G.Num_vex; i++)//循环所有顶点{if (lowcost[i] < min&& lowcost[i]!=0){min = lowcost[i];k = i;}}//找到了顶点vexs[k],就不需要再找连接顶点vexs[k]的边了,将lowcost[k]改为0,之后便不再改变,也不在参与找最小权值的过程lowcost[k] = 0;//已经得到了最小生成树的一条边,可以进行打印cout << "(" << G.vexs[adjvex[k]] << "," << G.vexs[k] << ")" << endl;for (int i = 1; i < G.Num_vex; i++)//循环所有顶点{if (G.arc[k][i] < lowcost[i] && lowcost[i] != 0){lowcost[i] = G.arc[k][i];//进行了交换说明lowcost数组中储存的边发生了改变,即顶点vexs[i]的双亲发生了改变,双亲变为了vexs[k]adjvex[i] = k;}}}
}
int main()
{MGraph G;Create_MGraph(G);MinBiTree_Prim(G);system("pause");return 0;
}

普里姆(Prim)算法(精讲)相关推荐

  1. 普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

    图是一种基础又重要的数据结构,图的生成树是图的一个极小连通子图.最小生成树是无向连通网的所有生成树中边的权值之和最小的一棵生成树.求图的最小生成树可以牵引出很多经典的题目,例如在N个城市之间建立通讯网 ...

  2. 【数据结构】克鲁斯卡尔(Kruskal)算法 —PK— 普里姆(Prim)算法

    目录 一.克鲁斯卡尔(Kruskal)算法 二.普里姆(Prim)算法 三.两个算法对比 求图的最小生成树的典型算法: 克鲁斯卡尔(Kruskal)算法 普里姆(Prim)算法 注:考虑问题的出发点相 ...

  3. 数据结构与算法(7-3)最小生成树(普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法)

    目录 一.最小生成树简介 二.普里姆算法(Prim) 1.原理 2.存储 2-1.图顶点和权: 2-3. 最小生成树: 3.Prim()函数 3-1.新顶点入树 3-2.保留最小权 3-3. 找到最小 ...

  4. 最小生成树——普里姆(Prim)算法

    Prim算法的基本思想是以顶点为主导地位:从起始顶点出发,通过选择当前可用的最小权值的边把其他顶点加入到生成树中来.设连通无向网为G(V,E),在普里姆算法中,将顶点集合V分成两个子集T和T'. (1 ...

  5. 一文带你弄懂普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

    Prim算法 Prim算法用于构造最小生成树,且适用于稠密图. 基本思想 : 归并顶点 设连通网络 N = { V, E } 从某顶点 u0 出发, 选择与它关联的具有最小权值的边(u0, v), 将 ...

  6. Java实现之普利姆(Prim)算法

    一.问题引入 1.问题引入 1)有胜利乡有7个村庄(A, B,C,D,E,F,G),现在需要修路把7个村庄连通 2)各个村庄的距离用边线表示(权),比如A-B距离5公里 3)问:如何修路保证各个村庄都 ...

  7. 算法:通过普利姆(Prim)算法,求出图的最小生成树

    请看如下的示例图,该图有 V1-V7 七个顶点,每个顶点之间的距离如图所示: 如果上面的图为七个城市的地理分布图,城市间相连的边上的数字为城市间的距离.我们要在这七个城市里面架设电线,使得每一个城市都 ...

  8. 最小生成树之Prim(普里姆)算法

    关于什么是Prim(普里姆算法)? 在实际生活中,我们常常碰到类似这种一类问题:如果要在n个城市之间建立通信联络网, 则连通n个城市仅仅须要n-1条线路.这时.我们须要考虑这样一个问题.怎样在最节省经 ...

  9. 用c语言描述普里姆算法和克鲁斯卡尔算法,克鲁斯卡尔算法+普里姆算法 详解

    克鲁斯卡尔算法: [1]克鲁斯卡尔算法 普里姆算法是以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树. 克鲁斯卡尔算法是直接以边为目标去构建. 因为权值是在边上,直接去找最小权值的边来构建生 ...

  10. 数据结构与算法|最小生成树算法(普里姆算法、克鲁斯卡尔算法)

    最小生成树算法 C语言代码部分来自小甲鱼的<数据结构与算法> 文章目录 最小生成树算法 一.普里姆(Prim)算法 1.C语言代码 2.算法思路 二.克鲁斯卡尔(Kruskal)算法 1. ...

最新文章

  1. Android应用程序消息处理机制(Looper、Handler)分析(1)
  2. Java线程详解(4)-线程状态的转换
  3. 2015年,戴尔存储如何助力“智慧视频”落地?
  4. Java命令行界面(第15部分):Jargo
  5. MVC5+EF6 入门完整教程四
  6. 这个天气怎么就这么热啊,哪里还有心情写代码呀。
  7. 基金小白要如何入门?
  8. SolarWinds 软件出现3个新的严重漏洞
  9. 下面的程序可以从0....n-1中随机等概率的输出m个不重复的数。(假设nm)
  10. 【算法理解】从头开始理解梯度提升算法
  11. ZooKeeper Watcher注意事项
  12. 编程软件有哪些比较好用
  13. 140个电脑小知识、小技巧(2)
  14. jsonp跨域原理(简单粗暴)
  15. 差分信号,差分对和耦合(一)——基本概念介绍
  16. Oracle RMAN无法删除归档一例
  17. 《C Primer Plus》第二章——C语言概述(程序示例与解释,提高程序可读性,函数的定义与使用,调试,关键字,复习题与编程练习)
  18. 数藏拐点已至,未来行业破局靠什么?
  19. 【iOS 开发】活动指示器控件 UIActivityIndicatorView
  20. 现在最流行的Java开发技术是什么?

热门文章

  1. VARIATIONAL AUTOENCODER FOR SPEECH ENHANCEMENT WITH A NOISE-AWARE ENCODER
  2. 转载 如何用示波器进行UART串口数据分析
  3. 2023.04.27 QT 制作文本编辑器
  4. Sja1000寄存器
  5. 我的创作纪念日-从写作到阿里云专家博主的故事
  6. ios pushViewController 页面不跳转问题解决
  7. 高人对四大杀毒软件的评价(卡巴 麦咖啡 诺顿 nod32)
  8. 微博桌面2015登录时显示“网络异常,请重新登录”,网络环境非常好,qq跟网页都正常开,为什么呢...
  9. 7-55 吉老师的回归 (15 分)
  10. 一场虚拟现实密室逃脱冒险,让你见识科技新加坡