目录

一、最小生成树

二、克鲁斯卡尔算法

1、思路

2、示例

3、C语言代码

三、普里姆算法

1、思路

2、C语言代码


一、最小生成树

一棵最小生成树需要满足哪些条件呢?

  • 不存在回路
  • 对于具有n个顶点的连通网,其生成树中只能有n-1条边,这n-1条边连通着n个顶点
  • 总的权值最小

判断是否会产生回路的方法为:

在初始状态下给每个顶点赋予不同的标记,对于遍历过程的每条边,其都有两个顶点,判断这两个顶点的标记是否一致,如果一致,说明它们本身就处在一颗树中,如果继续连接就会产生回路;如果不一致,说明它们之间还没有任何关系,可以连接。

二、克鲁斯卡尔算法

1、思路

  • 将所有边按权值大小进行升序排序
  • 判断是否构成回路
  • 直到有n-1条边

2、示例

3、C语言代码

#include <stdio.h>
#include <stdlib.h>
#define MAX_VERtEX_NUM 20
#define VertexType inttypedef struct Edge{VertexType initial;VertexType end;VertexType weight;
}edge[MAX_VERtEX_NUM];
//定义辅助数组
typedef struct {VertexType value;//顶点数据int sign;//每个顶点所属的集合
}assist[MAX_VERtEX_NUM];
assist assists;
//qsort排序函数中使用,使edges结构体中的边按照权值大小升序排序
int cmp(const void *a,const void*b){return  ((struct Edge*)a)->weight-((struct Edge*)b)->weight;
}
//初始化连通网
void CreateUDN(edge *edges,int *vexnum,int *arcnum){printf("输入连通网的顶点数和边数:\n");scanf("%d %d",&(*vexnum),&(*arcnum));printf("输入连通网的顶点:\n");for (int i=0; i<(*vexnum); i++) {scanf("%d",&(assists[i].value));assists[i].sign=i;}printf("输入各边的起始点和终点及权重(空格分隔):\n");for (int i=0 ; i<(*arcnum); i++) {scanf("%d %d %d",&(*edges)[i].initial,&(*edges)[i].end,&(*edges)[i].weight);}
}
//在assists数组中找到顶点point对应的位置下标
int Locatevex(int vexnum,int point){for (int i=0; i<vexnum; i++) {if (assists[i].value==point) {return i;}}return -1;
}void Kruskal ()
{int arcnum,vexnum;edge edges;CreateUDN(&edges,&vexnum,&arcnum);//对连通网中的所有边进行升序排序,结果仍保存在edges数组中qsort(edges, arcnum, sizeof(edges[0]), cmp);//创建一个空的结构体数组,用于存放最小生成树edge minTree;//设置一个用于记录最小生成树中边的数量的常量int num=0;//遍历所有的边for (int i=0; i<arcnum; i++) {//找到边的起始顶点和结束顶点在数组assists中的位置int initial=Locatevex(vexnum, edges[i].initial);int end=Locatevex(vexnum, edges[i].end);//如果顶点位置存在且顶点的标记不同,说明不在一个集合中,不会产生回路if (initial!=-1&& end!=-1&&assists[initial].sign!=assists[end].sign) {//记录该边,作为最小生成树的组成部分minTree[num]=edges[i];//计数+1num++;//将新加入生成树的顶点标记全不更改为一样的for (int k=0; k<vexnum; k++) {if (assists[k].sign==assists[end].sign) {assists[k].sign=assists[initial].sign;}}//如果选择的边的数量和顶点数相差1,证明最小生成树已经形成,退出循环if (num==vexnum-1) {break;}}}//输出语句printf("经克鲁斯卡尔算法得到最小生成树:\n");for (int i=0; i<vexnum-1; i++) {printf("%d->%d\n",minTree[i].initial,minTree[i].end);}return;
}int main(){Kruskal();return 0;
}

三、普里姆算法

1、思路

  • 将顶点分为两类,一类是在查找的过程中已经包含在树中的(假设为A类),剩下的为B类
  • 起始都为B类,选定任意一个点作为起始点,并将之从B类移至A类
  • 在B类中找到A类中的顶点之间权值最小的点,将之从B类移至A类,重复,直到B类中没有顶点

2、C语言代码 

#include <stdio.h>
#include <stdlib.h>
#define VertexType int
#define VRType int
#define MAX_VERtEX_NUM 20
#define InfoType char
#define INFINITY 65535
typedef struct {VRType adj;                             //对于无权图,用 1 或 0 表示是否相邻;对于带权图,直接为权值。InfoType * info;                        //弧额外含有的信息指针
}ArcCell,AdjMatrix[MAX_VERtEX_NUM][MAX_VERtEX_NUM];
typedef struct {VertexType vexs[MAX_VERtEX_NUM];        //存储图中顶点数据AdjMatrix arcs;                         //二维数组,记录顶点之间的关系int vexnum,arcnum;                      //记录图的顶点数和弧(边)数
}MGraph;
//根据顶点本身数据,判断出顶点在二维数组中的位置
int LocateVex(MGraph G,VertexType v){int i=0;//遍历一维数组,找到变量vfor (; i<G.vexnum; i++) {if (G.vexs[i]==v) {return i;}}return -1;
}
//构造无向网
void CreateUDN(MGraph* G){scanf("%d,%d",&(G->vexnum),&(G->arcnum));for (int i=0; i<G->vexnum; i++) {scanf("%d",&(G->vexs[i]));}for (int i=0; i<G->vexnum; i++) {for (int j=0; j<G->vexnum; j++) {G->arcs[i][j].adj=INFINITY;G->arcs[i][j].info=NULL;}}for (int i=0; i<G->arcnum; i++) {int v1,v2,w;scanf("%d,%d,%d",&v1,&v2,&w);int m=LocateVex(*G, v1);int n=LocateVex(*G, v2);if (m==-1 ||n==-1) {printf("no this vertex\n");return;}G->arcs[n][m].adj=w;G->arcs[m][n].adj=w;}
}
//辅助数组,用于每次筛选出权值最小的边的邻接点
typedef struct {VertexType adjvex;//记录权值最小的边的起始点VRType lowcost;//记录该边的权值
}closedge[MAX_VERtEX_NUM];
closedge theclose;//创建一个全局数组,因为每个函数中都会使用到
//在辅助数组中找出权值最小的边的数组下标,就可以间接找到此边的终点顶点。
int minimun(MGraph G,closedge close){int min=INFINITY;int min_i=-1;for (int i=0; i<G.vexnum; i++) {//权值为0,说明顶点已经归入最小生成树中;然后每次和min变量进行比较,最后找出最小的。if (close[i].lowcost>0 && close[i].lowcost < min) {min=close[i].lowcost;min_i=i;}}//返回最小权值所在的数组下标return min_i;
}
//普里姆算法函数,G为无向网,u为在网中选择的任意顶点作为起始点
void miniSpanTreePrim(MGraph G,VertexType u){//找到该起始点在顶点数组中的位置下标int k=LocateVex(G, u);//首先将与该起始点相关的所有边的信息:边的起始点和权值,存入辅助数组中相应的位置,例如(1,2)边,adjvex为0,lowcost为6,存入theclose[1]中,辅助数组的下标表示该边的顶点2for (int i=0; i<G.vexnum; i++) {if (i !=k) {theclose[i].adjvex=k;theclose[i].lowcost=G.arcs[k][i].adj;}}//由于起始点已经归为最小生成树,所以辅助数组对应位置的权值为0,这样,遍历时就不会被选中theclose[k].lowcost=0;//选择下一个点,并更新辅助数组中的信息for (int i=1; i<G.vexnum; i++) {//找出权值最小的边所在数组下标k=minimun(G, theclose);//输出选择的路径printf("v%d v%d\n",G.vexs[theclose[k].adjvex],G.vexs[k]);//归入最小生成树的顶点的辅助数组中的权值设为0theclose[k].lowcost=0;//信息辅助数组中存储的信息,由于此时树中新加入了一个顶点,需要判断,由此顶点出发,到达其它各顶点的权值是否比之前记录的权值还要小,如果还小,则更新for (int j=0; j<G.vexnum; j++) {if (G.arcs[k][j].adj<theclose[j].lowcost) {theclose[j].adjvex=k;theclose[j].lowcost=G.arcs[k][j].adj;}}}printf("\n");
}
int main(){MGraph G;CreateUDN(&G);miniSpanTreePrim(G, 1);
}

最小生成树:克鲁斯卡尔算法+普里姆算法相关推荐

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

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

  2. 最小生成树(克鲁斯卡尔算法 普里姆算法)

    最小生成树是处理图结构中,简化图的算法:即删除一些边使得图得以简化,但应保证图中任意点都是相连通的.形成的最小生成树应该使得从顶点遍历时走过边的权值和最小.(有n个节点,则最小生成树的边数应为n-1) ...

  3. 最小生成树算法——普里姆算法

    普里姆算法 假设G=(V,E)是一个具有n个顶点的连通网,T=(U,TE)是G的最小生成树,其中U是T的顶点集,TE是T的边集,U和TE的初始值为空.算法过程: 首先从V中任取一个顶点(假定v1),将 ...

  4. 最小生成树(详解普里姆算法)

    首先,我们来看一下图的一些基本知识点: 图:图 G=(V,E) 由顶点集 V 和边集 E 组成.每条边对应一个点对 (v,w),其中 v,w 属于 V .如果图中的点对是有序的,那么该图就是有向图,反 ...

  5. 算法 - 普里姆算法(修路问题求解)

    从A开始,A作为定点,找到与A相连并且未被处理(不在顶点集合中)的进行处理,找到权值最小的并加入集合,A-C[7].A-G[2].A-B[5],最小的是A-G[2],所以把G加入集合,这里是有A-G的 ...

  6. 【数据结构】最小生成树(Prim算法,普里姆算法,普利姆)、最短路径(Dijkstra算法,迪杰斯特拉算法,单源最短路径)

    文章目录 前置问题 问题解答 一.基础概念:最小生成树的定义和性质 (1)最小生成树(Minimal Spanning Tree)的定义 (2)最小生成树(MST)的性质 二.如何利用MST性质寻找最 ...

  7. 学渣都能看懂的-最小生成树Prim算法(普里姆算法)

    最小生成树问题:要将图中的n个点连通,即任意两点之间都存在路径.要使连通图中各边的权值之和最小. 例: 最小生成树所要掌握的点: ·求出最小生成树权值之和 ·保存最小生成树的各边 使各边权值之和最短需 ...

  8. 最小生成树(普里姆算法【Prim】与克鲁斯卡尔算法【Kruskal】)

    写在前面:博主是一位普普通通的19届双非软工在读生,平时最大的爱好就是听听歌,逛逛B站.博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的事,做自己不后悔的事 ...

  9. 两种构造最小生成树的算法(普里姆算法,克鲁斯卡尔算法)

    (一)普里姆算法 普里姆算法求最小生成树:从生成树中只有一个顶点开始,到定点全部进入生成数为止: 2.克鲁斯卡尔算法. 思想:将所有边按其权值从小到大排一遍,从小到大依次选取边,加入最小生成树中,若加 ...

最新文章

  1. 线性布局上的一个小错误
  2. LeetCode--024--两两交换链表中的节点(java)
  3. 学校通知,本学期不用返校了
  4. Java HashMap的put操作(Java1.8)
  5. P1282 多米诺骨牌 (差值DP+背包)
  6. 帐号体系:后端信息结构设计
  7. PowerDesigner模型设计
  8. Oracle全库导入表报错 ORA-39126
  9. Windows 10 常用的快捷键及常用指令
  10. 关于c/s vs web 程序的并发问题
  11. Spring Boot war方式打包发布
  12. pom.xml中依赖的optionaltrue/optional标签
  13. MaxCompute 2.0 生态开放之路及最新发展
  14. Java获取http和https协议返回的json数据
  15. 软件测试方法可以分为几种?
  16. mix2线刷开发板救砖_小米MIX2官方原厂系统rom线刷刷机包降级包下载8.10.25版
  17. Java 给PPT添加动画效果(预设动画/自定义动画)
  18. 如何进行航拍全景摄影(上)
  19. android第三方库适配鸿蒙,鸿蒙第三方适配rom
  20. 中国提取市场趋势报告、技术动态创新及市场预测

热门文章

  1. 调用NMAP批量扫描IP端口
  2. 阿里OCR接入一个小注意事项
  3. Python就是牛,2行Python就能实现 文本文件 差异对比!
  4. EXCEL下拉框多选
  5. CUDA安装失败,解决办法
  6. 超大型数据中心正在改变精密空调市场
  7. CLAHE算法实现图像增强「AI工程论」
  8. 樱桃键盘驱动在哪下_闭着眼睛也能买的樱桃轴机械键盘——GANSS GS87C分享
  9. 让你的Lable拥有qq表情!
  10. 成功不是偶然的,它是从寂寞中成长起来的花朵-----王选