46. 蛤蟆的数据结构笔记之四十六普里姆算法

46. 蛤蟆的数据结构笔记之四十六普里姆算法

本篇名言:“手莫伸 ,伸手必被捉。党与人民在监督 ,万目睽睽难逃脱。汝言惧捉手不伸
,他道不伸能自觉 ,
其实想伸不敢伸 ,人民咫尺手自缩。--
陈毅”

连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边。所谓的最小成本,就是n个顶点,用n-1条边把一个连通图连接起来,并且使得权值的和最小。构造连通网的最小代价生成树,即最小生成树(Minimum Cost Spanning Tree)。

找连通图的最小生成树,经典的有两种算法,普里姆算法和克鲁斯卡尔算法,这里介绍克里姆算法。这篇我们来看下最小生成树的另一个算法,普里姆算法。

欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47092633

1.  普里姆算法

1.1             Prim 算法思想

设 G=( V,E )是一个有 n 个顶点的连通图,用T=(U,TE)表示要构造的最小生成树,其中 U 为顶点集合,TE 为边的集合。则 Prim 算法的具体步骤描述入下:

1.        初始化:令 U={?},TE={?}。从 V 中取出一个顶点u0 放入生成树的顶点集 U 中,作为第一个顶点,此时T=  ({u0}) ,{φ});

2.        从 u ∈U ,  v ∈(v ? V ) 的边(u,v)中找一条代价最小的边(u*,v*),将其放入 TE 中,并将v*放入 U 中;

3.        重复步骤(2),直至 U=V 为止。此时集合 TE 中必有 n-1 条边,T 即为所要构造的最小生成树。

通俗讲法:可取图中任意一个顶点V作为生成树的根,之后若要往生成树上添加顶点W,则在顶点V和W之间必定存在一条边。并且该边的权值在所有连通顶点V和W之间的边中取值最小。

一般情况下,假设n个顶点分成两个集合:U(包含已落在生成树上的结点)和V-U(尚未落在生成树上的顶点),则在所有连通U中顶点和V-U中顶点的边中选取权值最小的边。

生成树的过程如下图1

如下图2所示为构造生成树的过程中,辅助数组中各分量值的变化情况,初始归U={v1},加入到U集合中的节点,我们将lowcost改成0以示:

2.  代码实现

2.1         Prim函数

定义顶点个数为6个,边的数量为10条。

输入每个顶点的名字。

设置该点到任意其他一个顶点间的举例为无限大。

设置指定点之间的距离,即邻接矩阵。

进入核心代码:

将v0顶点与之有边的权值存入数组,

设置数组lowcost存放边的权值,adjvex存放顶点的序号。

Adjvex[v]为U中距离V最近的一个邻接点,及是边(v,adjvex[v]),最小权值为lowcost[v]

lowcost 保存 顶点集合内顶点到生成树外各顶点的各边上的当前最小权值。

Adjvex保存 顶点集合外各顶点距离集合内哪个顶点最近。

进入主循环,从第一个点开始:

从V0顶点开始(V0加入到最小生成树),lowcost保存和V0其他顶点的边权值。

lowcost:0 6 1 5 N N

Adjvex:0 0 0 0 0 0

然后找到与V0最近的点V2,权值为1.同时把lowcost[2]=0,表示V2加入到了最小生成树中。

然后依次比较所有和V0,V2的其他顶点的权值,取较小的权值值存放到lowcost数组中。

如果V2到某个点的距离比V0到某个点的距离要小,则设置Adjvex [某个点] = 2,表示那个店和V2链接着。

结束后:lowcost: 0 5 0 56 4

Adjvex: 0 2 0 0 2 2

然后进入下一个点,下个点是和V2点连接权值最小为4的点,该点就是V5点。同时将V5加入到最小生成树中。

然后比较V5和所有其他节点的权值与lowcost对比。发现V5到V3的距离为2,而lowcost中记载的却是5,所示将lowcost[3]=2.

lowcost: 0 5 0 2 6 0

Adjvex: 0 2 0 5 2 2

然后进入V3点的循环,权值最小为2的点,该点就是V3点,同时V3加入最小生成树中。

然后比较V3和所有其他节点的权值与lowcost对比,此时剩余点到最小生成树的距离都比到V3点要小。

lowcost: 0 5 0 0 6 0

Adjvex: 0 2 0 5 2 2

接着:找到此时的lowcost最小为5,是当前最小生成树到V1的点, 同时V1加入最小生成树中。

此时:

lowcost: 0 0 0 0 6 0

Adjvex: 0 2 0 5 2 2

比较V1和剩余未在最小生成树点的权值与lowcost对比(其实只剩下V4点),发现V1其实比最小生成树到剩余点V4的距离近,那么设置adjvex[4]=1,lowcost[4]=3。

lowcost: 0 0 0 0 3 0

Adjvex: 0 2 0 5 1 2

最后,找到lowcost最小为3,也是剩余的到顶点V4的权值,
V4加入最小生成树中。

lowcost: 0 0 0 0 0 0

Adjvex: 0 2 0 5 1 2

循环结束,退出。

PS: Adjvex数组0 2 0 0 2 2表示当前最小生成树中有点V0,V2。其中V1连着V2,V4连着V2,V5连着V2。

Adjvex数组0 2 0 5 2 2 表示当前最小生成树中有点V0,V2,V5。其中V1连着V2,V3连着V5,V4连着V2,V5连着V2。

lowcost:0 5 0 5 6 4 表示当前V0,V2在当前生成树中,最小生成树到V1为5,最小生成树到V3为5,最小生成树到V4为6,最小生成树到V5为4.

lowcost:0 5 0 2 6 0,表示当前V0,V2,V5在当前生成树中,最小生成树到V1为5,最小生成树到V3为2,最小生成树到V4为6

最后如下图3所示:

3.  源码

#defineINFINITY65535

typedefint
status;

#include<stdio.h>

#include<stdlib.h>

#include<conio.h>

#include"string.h"

#definemaxlen10

typedefstruct

{

charvexs[maxlen][maxlen];/*顶点信息集合,我们用它来存入顶点名字*/

intvexnum,arcnum;/*顶点数和边数*/

intarcs[maxlen][maxlen];/*邻接矩阵*/

}graph;

//定位输入节点的名称

int LocateVex(graphG,charu[maxlen])

{

inti;

for(i=0;i<G.vexnum;++i)

if(strcmp(u,G.vexs[i])==0)

returni;

return-1;

}

void prim(graph&g)/*最小生成树*/

{

inti,j,k,min,w,flag;

intlowcost[maxlen];/*权值*/

intadjvex[maxlen];/*最小生成树结点*/

charva[maxlen],vb[maxlen];

//初始化邻接矩阵

//printf("请输入顶点数和边数:\n");

//scanf("%d%d",&g.vexnum,&g.arcnum);

g.vexnum=6;

g.arcnum=10;

i = 1;

printf("请输入顶点信息:\n");

for(intj=0;j<g.vexnum;j++)

scanf("%s",g.vexs[j]);

for(i=0;i<g.vexnum;++i)

for(j=0;j<g.vexnum;++j)//初始化邻接矩阵

{

g.arcs[i][j]=INFINITY; //任意两个顶点间距离为无穷大。

}//for

/*

printf("请输入%d条弧的弧尾弧头权值(以空格为间隔)\n",g.arcnum);

for(k=0;k<g.arcnum;++k)

{

scanf("%s%s%d%*c",va,vb,&w);//用%*c吃掉回车符

i=LocateVex(g,va);  //注意,这里定义的是charva[5],也就是说va是首地址

j=LocateVex(g,vb);

g.arcs[i][j]=w;//无向网

g.arcs[j][i]=w;//无向网

}//for

*/

g.arcs[0][1]=6;

g.arcs[1][0]=6;

g.arcs[0][2]=1;

g.arcs[2][0]=1;

g.arcs[0][3]=5;

g.arcs[3][0]=5;

g.arcs[1][2]=5;

g.arcs[2][1]=5;

g.arcs[1][4]=3;

g.arcs[4][1]=3;

g.arcs[2][3]=5;

g.arcs[3][2]=5;

g.arcs[2][4]=6;

g.arcs[4][2]=6;

g.arcs[2][5]=4;

g.arcs[5][2]=4;

g.arcs[3][5]=2;

g.arcs[5][3]=2;

g.arcs[4][5]=6;

g.arcs[5][4]=6;

printf("最小生成树的边为:\n");

for(i=1;i<g.vexnum;i++)

{

lowcost[i]=g.arcs[0][i];

adjvex[i]=0;

}

lowcost[0]=0;

adjvex[0]=0;

for(i=1;i<g.vexnum;i++)

{

j= 1;

min=65535;

k=0;

while(j<g.vexnum)

{

if(lowcost[j]!= 0 && lowcost[j]<min)

{

min=lowcost[j];

k= j;

}

++j;

}

printf("(%d,%d)",adjvex[k],k);

lowcost[k]= 0;

for (j = 1; j<g.vexnum;++j)

{

if(lowcost[j]!=0&&
g.arcs[k][j]<lowcost[j])

{

lowcost[j]=g.arcs[k][j];

adjvex[j]=k;

}

}

}

}

int main()

{

graphg;

prim(g);

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-26 06:46:29

46. 蛤蟆的数据结构笔记之四十六普里姆算法的相关文章

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先 本篇名言:"生活真象这杯浓酒 ,不经三番五次的提炼呵 , 就不会这样一来可口 ! -- 郭小川" 继续看下广度优先的遍历,上篇我们看了深度遍历是每次一个节点的链表是走到底的. 欢迎转载,转载请标明出处:http://write.blog.csdn.net/postedit/47029275 1.  原理 首先,从图的某个顶点v0出发,访问了v0之后,依次访问与v0相邻的未被访问的顶点,然后分别从这些顶点出发,广度优先遍历,直至所有的

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径 本篇名言:"富贵不淫贫贱乐 ,男儿到此是豪雄.-- 程颢" 这次来看下有向无环图的另一个应用关键路径. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47135061 1.  关键路径 与AOV-网相对应的是AOE-网(Activity On Edge)即边表示活动的网.AOE-网是一个带权的有向无环图,其中,顶点表示事件(Event),弧表示活动,权表

49. 蛤蟆的数据结构笔记之四十九图的连通性问题

49. 蛤蟆的数据结构笔记之四十九图的连通性问题 本篇名言:"我们不得不饮食.睡眠.游惰.恋爱,也就是说,我们不得不接触生活中最甜蜜的事情:不过我们必须不屈服于这些事物 .....--约里奥?居里"     此篇就作为数据结构入门笔记的最后一篇吧. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47135259 设图G=(V,E)是一个无向图,G的一个连通分支是一个最大的连通子图,即一个连通分支是不包含在任何更大的

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法 本篇名言:"希望是厄运的忠实的姐妹. --普希金" 我们继续来看下数据结构图中的一个算法,这个算法来自图灵奖得主. 1.  Floyd算法介绍 Floyd算法又称为插点法,是一种用于寻找给定的加权图中多源点之间最短路径的算法.该算法名称以创始人之一.1978年图灵奖获得者.斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名.注意这个可不是心理学的那个弗洛伊德. 是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径

16、蛤蟆的数据结构笔记之十六栈的应用之栈与递归之汉诺塔问题

16.蛤蟆的数据结构笔记之十六栈的应用之栈与递归之汉诺塔问题 本篇名言:"人生的价值,并不是用时间,而是用深度去衡量的." 继续栈与递归应用,汉诺塔问题. 欢迎转载,转载请标明出处: 1.  汉诺塔问题 汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上.并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一

45. 蛤蟆的数据结构笔记之四十五克鲁斯卡尔算法

本篇名言:"假如生活欺骗了你 ,不要忧郁 , 也不要愤慨 !不顺心的时候暂且容忍 : 相信吧 , 快乐的日子就会到来.--普希金" 上两篇学习了弗洛伊德和迪杰特斯拉算法.这次来看下克鲁斯卡尔算法. 欢迎转载,转载请标明出处:http://write.blog.csdn.net/postedit/47071539 1.  克鲁斯卡尔算法 克鲁斯卡尔(Kruskal)算法是在剩下的所有未选取的边中,找最小边,如果和已选取的边构成回路,则放弃,选取次小边.是实现图的最小生成树最常用的算法.

41 蛤蟆的数据结构笔记之四十一图的遍历之深度优先

41  蛤蟆的数据结构笔记之四十一图的遍历之深度优先 本篇名言:"对于我来说 , 生命的意义在于设身处地替人着想 , 忧他人之忧 , 乐他人之乐. -- 爱因斯坦" 上篇我们实现了图的邻接多重表表示图,以及深度遍历和广度遍历的代码,这次我们先来看下图的深度遍历. 欢迎转载,转载请标明出处: 1.  原理 图遍历又称图的遍历,属于数据结构中的内容.指的是从图中的任一顶点出发,对图中的所有顶点访问一次且只访问一次.图的遍历操作和树的遍历操作功能相似.图的遍历是图的一种基本操作,图的许多其它

34. 蛤蟆的数据结构笔记之三十四树的概念

34. 蛤蟆的数据结构笔记之三十四树的概念 本篇名言:"过去属于死神,未来属于你自己.--雪莱" 本篇笔记开始我们要进入新的概念了,树!是不是有点小激动呢?让我们从概念开始吧 当然概念要理解,如果当前不能立刻理解,可以后续结合代码一起理解效果更佳. 1.  树型结构 之前我们学习的那么多,其实都是线性数据结构. 树 则不同,它是非线性结构. 树形结构指的是数据元素之间存在着"一对多"的树形关系的数据结构,是一类重要的非线性数据结构.在树形结构中,树根结点没有前驱结点

18、蛤蟆的数据结构笔记之十八链表实现稀疏矩阵

18.蛤蟆的数据结构笔记之十八链表实现稀疏矩阵 本篇名言:"必须如蜜蜂一样,采过许多花,才能酿出蜜来." 上篇中实现了栈在多项式实现中的例子,再来看下稀疏矩阵通过链表方式实现. 关键字:十字链表存储 欢迎转载,转载请标明出处: 1.  十字链表存储 十字链表(OrthogonalList)是有向图的另一种链式存储结构.该结构可以看成是将有向图的邻接表和逆邻接表结合起来得到的.用十字链表来存储有向图,可以达到高效的存取效果.同时,代码的可读性也会得到提升. 为便于理解后续代码,从网上摘了