连通图的生成树:

是一个极小的连通图,它含有图中全部的N个顶点,但是只足以构成一颗树的N-1条边。

必须满足三个条件:

  1. 图是连通图;
  2. 图中包含了N个结点
  3. 图中边的数量等于N-1条。

连通图生成树的判断:

下面4幅图中哪个是连通图的最小生成树?

图1
图2
图3
图4

满足最小生成树的三个条件的只有图2。所以图2是连通图的最小生成树。

阿里的面试题

假设目前优N个顶点,每个顶点链接的路径不一样,请你设计一个算法,快速找出能覆盖所以顶点的路径。

阿里面试题

注意:该题并不是求两点间的最短路径,而是设计一个路线,能够覆盖所有顶点。

方案一:

方案一

11+26+20+22+18+21+24+19 = 161

方案二:

方案二

8+12+10+11+17+19+16+7=100

方案三:

方案三

8+12+10+11+16+19+16+7=99

上面三种方案中,第三种为最优解。

那么有没有一种算法能精准的算出网图的最优解呢?

方法就是最小生出树,即把连通图以最小代价生出的树,叫做最小生成树

保存图

先把上面的图用邻接矩阵存储起来。关于邻接矩阵存图,可以看我上篇文章【图的存储】相关内容。

GhostClock:经典数据结构-图​zhuanlan.zhihu.com

最后得到结构为:

用邻接矩阵存储图

数据结构:

#include "math.h"
#include "time.h"#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0#define MAXEDGE 20
#define MAXVEX 20
#define INFINITYC 65535typedef int Status;    /* Status是函数的类型,其值是函数结果状态代码,如OK等 */typedef struct
{int arc[MAXVEX][MAXVEX];int numVertexes, numEdges;
}MGraph;

创建邻接矩阵:

/*创建邻接矩阵*/
void CreateMGraph(MGraph *G)/* 构件图 */
{int i, j;/* printf("请输入边数和顶点数:"); */G->numEdges=15;G->numVertexes=9;for (i = 0; i < G->numVertexes; i++)/* 初始化图 */{for ( j = 0; j < G->numVertexes; j++){if (i==j)G->arc[i][j]=0;elseG->arc[i][j] = G->arc[j][i] = INFINITYC;}}G->arc[0][1]=10;G->arc[0][5]=11;G->arc[1][2]=18;G->arc[1][8]=12;G->arc[1][6]=16;G->arc[2][8]=8;G->arc[2][3]=22;G->arc[3][8]=21;G->arc[3][6]=24;G->arc[3][7]=16;G->arc[3][4]=20;G->arc[4][7]=7;G->arc[4][5]=26;G->arc[5][6]=17;G->arc[6][7]=19;for(i = 0; i < G->numVertexes; i++){for(j = i; j < G->numVertexes; j++){G->arc[j][i] =G->arc[i][j];}}}

普里姆(Prim)算法

思路:

  1. 定义两个数组,lowcost,arjvex;arjvex用来保存顶点下标;lowcost用开保存顶点之间的权值;
  2. 初始化两个数组,从v0开始寻找最小生成树,默认v0是最小生成树上的第一顶点;
  3. 循环lowcost数组,根据权值找到顶点k;
  4. 更新lowcost数组;
  5. 循化所有顶点,找到与顶点k有关的顶点,并更新lowcost数组和arjvex数组。

注意:
更新lowcost数组与arjvex的条件
1.与顶点k之间有链接
2.当前结点j没有加入过最小生成树
3.顶点k与当前顶点j之间的权值小于顶点j与其他顶点k之间的权值,则更新。(简单说就是要比较之前存储的值要小,则更新)。

将与V0相关的V1-V8的所有顶点赋值对应的权值,并且arjvex[1~8]都赋值为0,表示都是与顶点V0相关的顶点。如下图所示:

V0相关的V1-V8顶点

如上图所示,这里定义两个数组【lowcost,arjvex】,数组lowcost存顶点之间的权值,数组arjvex保存相关顶点下标

/* Prim算法生成最小生成树 */
void MiniSpanTree_Prim(MGraph G)
{int min, i, j, k;int sum = 0;/* 保存相关顶点下标 */int adjvex[MAXVEX];/* 保存相关顶点间边的权值 */int lowcost[MAXVEX];/* 初始化第一个权值为0,即v0加入生成树 *//* lowcost的值为0,在这里就是此下标的顶点已经加入生成树 */lowcost[0] = 0;/* 初始化第一个顶点下标为0 */adjvex[0] = 0;//1. 初始化for(i = 1; i < G.numVertexes; i++)    /* 循环除下标为0外的全部顶点 */{lowcost[i] = G.arc[0][i];    /* 将v0顶点与之有边的权值存入数组 */adjvex[i] = 0;                    /* 初始化都为v0的下标 */}//2. 循环除了下标为0以外的全部顶点, 找到lowcost数组中最小的顶点kfor(i = 1; i < G.numVertexes; i++){/* 初始化最小权值为∞, *//* 通常设置为不可能的大数字如32767、65535等 */min = INFINITYC;j = 1;k = 0;while(j < G.numVertexes)    /* 循环全部顶点 */{/* 如果权值不为0且权值小于min */if(lowcost[j]!=0 && lowcost[j] < min){/* 则让当前权值成为最小值,更新min */min = lowcost[j];/* 将当前最小值的下标存入k */k = j;}j++;}/* 打印当前顶点边中权值最小的边 */printf("(V%d, V%d)=%dn", adjvex[k], k ,G.arc[adjvex[k]][k]);sum+=G.arc[adjvex[k]][k];/* 3.将当前顶点的权值设置为0,表示此顶点已经完成任务 */lowcost[k] = 0;/* 循环所有顶点,找到与顶点k 相连接的顶点1. 与顶点k 之间连接;2. 该结点没有被加入到生成树;3. 顶点k 与 顶点j 之间的权值 < 顶点j 与其他顶点的权值,则更新lowcost 数组;*/for(j = 1; j < G.numVertexes; j++){/* 如果下标为k顶点各边权值小于此前这些顶点未被加入生成树权值 */if(lowcost[j]!=0 && G.arc[k][j] < lowcost[j]){/* 将较小的权值存入lowcost相应位置 */lowcost[j] = G.arc[k][j];/* 将下标为k的顶点存入adjvex */adjvex[j] = k;}}}printf("sum = %dn",sum);
}

使用并打印

printf("最小生成树_Prim算法n");
MGraph G;
CreateMGraph(&G);
MiniSpanTree_Prim(G);

打印

克鲁斯卡尔(Kruskal)算法

思路:

  1. 将邻接矩阵转换为数组;
  2. 对边表数组根据权值按照从小到大的顺序排列
  3. 遍历所有边,通过parent数组找到边的链接信息,避免闭环;
  4. 如果不存在闭环问题,则加入到最小生成树中,并且修改parent数组。

边表的定义:

/* 对边集数组Edge结构的定义 */
typedef struct
{int begin;int end;int weight;
}Edge ;

生成最小生成树

/* 生成最小生成树 */
void MiniSpanTree_Kruskal(MGraph G)
{int i, j, n, m;int sum = 0;int k = 0;/* 定义一数组用来判断边与边是否形成环路用来记录顶点间的连接关系. 通过它来防止最小生成树产生闭环;*/int parent[MAXVEX];/* 定义边集数组,edge的结构为begin,end,weight,均为整型 */Edge edges[MAXEDGE];/*1. 用来构建边集数组*/for ( i = 0; i < G.numVertexes-1; i++){for (j = i + 1; j < G.numVertexes; j++){//如果当前路径权值 != ∞if (G.arc[i][j]<INFINITYC){//将路径对应的begin,end,weight 存储到edges 边集数组中.edges[k].begin = i;edges[k].end = j;edges[k].weight = G.arc[i][j];//边集数组计算器k++;k++;}}}//2. 对边集数组排序sort(edges, &G);//3.初始化parent 数组为0. 9个顶点;// for (i = 0; i < G.numVertexes; i++)for (i = 0; i < MAXVEX; i++)parent[i] = 0;//4. 计算最小生成树printf("打印最小生成树:n");/* 循环每一条边 G.numEdges 有15条边*/for (i = 0; i < G.numEdges; i++){//获取begin,end 在parent 数组中的信息;//如果n = m ,将begin 和 end 连接,就会产生闭合的环.n = Find(parent,edges[i].begin);m = Find(parent,edges[i].end);//printf("n = %d,m = %dn",n,m);/* 假如n与m不等,说明此边没有与现有的生成树形成环路 */if (n != m){/* 将此边的结尾顶点放入下标为起点的parent中。 *//* 表示此顶点已经在生成树集合中 */parent[n] = m;/*打印最小生成树路径*/printf("(%d, %d) %dn", edges[i].begin, edges[i].end, edges[i].weight);sum += edges[i].weight;}}printf("sum = %dn",sum);
}

工具方法

/* 交换权值以及头和尾 */
void Swapn(Edge *edges,int i, int j)
{int tempValue;//交换edges[i].begin 和 edges[j].begin 的值tempValue = edges[i].begin;edges[i].begin = edges[j].begin;edges[j].begin = tempValue;//交换edges[i].end 和 edges[j].end 的值tempValue = edges[i].end;edges[i].end = edges[j].end;edges[j].end = tempValue;//交换edges[i].weight 和 edges[j].weight 的值tempValue = edges[i].weight;edges[i].weight = edges[j].weight;edges[j].weight = tempValue;
}/* 对权值进行排序 */
void sort(Edge edges[],MGraph *G)
{//对权值进行排序(从小到大)int i, j;for ( i = 0; i < G->numEdges; i++){for ( j = i + 1; j < G->numEdges; j++){if (edges[i].weight > edges[j].weight){Swapn(edges, i, j);}}}printf("边集数组根据权值排序之后的为:n");for (i = 0; i < G->numEdges; i++){printf("(%d, %d) %dn", edges[i].begin, edges[i].end, edges[i].weight);}}/* 查找连线顶点的尾部下标 */
//根据顶点f以及parent 数组,可以找到当前顶点的尾部下标; 帮助我们判断2点之间是否存在闭环问题;
int Find(int *parent, int f)
{while ( parent[f] > 0){f = parent[f];}return f;
}

使用并打印:

printf("Hello,最小生成树_Kruskal算法n");
MGraph G;
CreateMGraph(&G);
MiniSpanTree_Kruskal(G);

打印最小生成树_Kruskal算法

生成随机数放入整型数组怎么判断有没有重复_图的应用(1)-连通图的最小生成树(Prim算法和Kruskal算法)...相关推荐

  1. python fun函数、求4x4整型数组的主对角线元素的和_求一个4×4的整型二维数组主对角线元素之和...

    展开全部 下面是Java语言编写一个计算4*4整型数组对角线636f70793231313335323631343130323136353331333431353338元素和的代码: import j ...

  2. python fun函数、求4x4整型数组的主对角线元素的和_输入4行4列的二维数组,求计算主对角线各元素之和,计算副对角线各元素之和。...

    展开全部 #include<stdio.h> int main(void) { int a[4][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; ...

  3. 编写一个C程序,实现以下功能: 编写一个函数jugde(int b[],int n),该函数能将一个一维整型数组调整为左右两边,凡是奇数均放左边,凡是偶数均放在右边。

    题目如下: 编写一个C程序,实现以下功能: 编写一个函数jugde(int b[],int n),该函数能将一个一维整型数组调整为左右两边,凡是奇数均放左边,凡是偶数均放在右边.(注:奇.偶数的个数不 ...

  4. c语言去掉数组中重复的,C语言删除无序整型数组中的重复元素及时间复杂度

    数组重复的问题在任何编程中都会有碰到了,这里介绍C语言删除无序整型数组中的重复元素及时间复杂度,希望对各位有帮助. 遇到一个题,大概要求是写一个函数处理来去掉一个无序的整型数组(例如int i_arr ...

  5. Python产生100个1—100的随机数放入列表Num中,输出列表中的数,然后将它们排序,并输出排序结果。

    import random #内建函数 Num=[] for i in range(101):Num.append(random.randint(1,100)) #append()将参数添加到列表末尾 ...

  6. 一个整型数组里除了两个数字之外,其他的数字都出现了两次

    题目: 一个整型数组里除了两个数字之外,其他的数字都出现了两次 解答: 我们从头到尾异或数组中的每个数字,那么最终的结果是两个只出现一次数字的异或的结果,由于两个数字不一样,那么异或的结果肯定不为0, ...

  7. 输入整型数组和排序标识,对其元素按照升序或降序进行排序(华为OJ系列)

    输入整型数组和排序标识,对其元素按照升序或降序进行排序接口说明原型:void sortIntegerArray(Integer[] pIntegerArray, int iSortFlag);输入参数 ...

  8. 指针||指针和数组||指针和函数||指针、数组、函数 案例描述:封装一个函数,利用冒泡排序,实现对整型数组的升序排序

    指针 指针的基本概念 指针的作用: 可以通过指针间接访问内存 内存编号是从0开始记录的,一般用十六进制数字表示 可以利用指针变量保存地址 指针变量的定义和使用 指针变量定义语法: 数据类型 * 变量名 ...

  9. Interview:算法岗位面试—10.30上午上海某信息公司(偏图算法)技术面试之单链表反转、给定整型数组和目标值 二分法查找+下午上海某金融公司(AI岗位,上市)CTO和主管技术面试之Xcepti

    ML岗位面试:10.30上午上海某信息公司(偏图算法)技术面试之单链表反转.给定整型数组和目标值 二分法查找+下午上海某金融公司(AI岗位,上市)CTO和主管技术面试之Xception.推荐算法等 I ...

最新文章

  1. matlab文档型数据导入,MATLAB-数据导入
  2. AI一分钟 | NLP先驱Aravind Joshi教授去世,曾获ACL终身成就奖;年度花木兰诞生,甘薇全权负责贾跃亭的一地鸡毛
  3. NLP诗词生成模型数据准备及实战
  4. python基础学习-装饰器进阶
  5. 聚类 | 超详细的性能度量和相似度方法总结
  6. 从零开始学习Oracle—安装及删除
  7. javascript库之Mustache库使用说明
  8. java简单纸牌游戏_活动回顾 | 畅玩法语纸牌游戏
  9. Java编码与乱码问题
  10. c++ 15个语言特性,C++11/14的新特性(更简洁)
  11. matlab imrotate中心,MATLAB imrotate函数的用法
  12. linux find命令按文件内容查找,linux下的find文件查找命令与grep文件内容查找命令...
  13. 攻防技术第一篇之-知彼(攻击手段)
  14. Weiss Ratings公布加密货币评级结果
  15. 华为18级大牛倾情奉送:分布式服务框架和微服务设计原理实战文档,啃完发现涨薪如此简单
  16. mongodb 分组获取最新一条的数据
  17. Python爬虫进阶——urllib模块使用案例【淘宝】
  18. 04.声明式服务调用:Spring Cloud Feign(Greenwich.SR2)
  19. Red Hat Linux 7.3 +VMWare 虚拟机安装实践
  20. 从搜索引擎打击论坛外链看se规范行业

热门文章

  1. java企业网站源码,模版,有前后台,springmvcSSM,生成静态化
  2. XAMPP下的MYSQL解决中文乱码问题
  3. Git中忽略文件权限或文件拥有者的改变
  4. Centos6.5 安装配置docker
  5. android中volley通信框架简介
  6. Script:找出ASM中的Spfile参数文件
  7. Spark源码阅读02-Spark核心原理之调度算法
  8. 安装第三方包查看python版本/第三方包版本
  9. 同样的代码,conda无法运行,命令行却可以运行
  10. Python 条件判断