2023年8月1日发(作者:)
克鲁斯卡尔算法(Kruskal)详解应⽤场景-公交站问题看⼀个应⽤场景和问题:1) 某城市新增 7 个站点 (A, B, C, D, E, F, G) ,现在需要修路把 7 个站点连通2) 各个站点的距离⽤边线表⽰ ( 权 ) ,⽐如 A – B 距离 12 公⾥3) 问:如何修路保证各个站点都能连通,并且总的修建公路总⾥程最短 ?
克鲁斯卡尔算法介绍1) 克鲁斯卡尔 (Kruskal) 算法,是⽤来求加权连通图的最⼩⽣成树的算法 。2) 基本思想 :按照权值从⼩到⼤的顺序选择 n-1 条边,并保证这 n-1 条边不构成回路3) 具体做法 :⾸先构造⼀个只含 n 个顶点的森林,然后依权值从⼩到⼤从连通⽹中选择边加⼊到森林中,并使森林中不产⽣回路,直⾄森林变成⼀棵树为⽌
克鲁斯卡尔算法图解说明以城市公交站问题来图解说明 克鲁斯卡尔算法的原理和步骤:在含有n个顶点的连通图中选择n-1条边,构成⼀棵极⼩连通⼦图,并使该连通⼦图中n-1条边上权值之和达到最⼩,则称其为连通⽹的最⼩⽣成树。
例如,对于如上图G4所⽰的连通⽹可以有多棵权值总和不相同的⽣成树。
克鲁斯卡尔算法图解以上图G4为例,来对克鲁斯卡尔进⾏演⽰(假设,⽤数组R保存最⼩⽣成树结果)。
第1步:将边
边
第2步:将边
上⼀步操作之后,边
第3步:将边
上⼀步操作之后,边
第4步:将边加⼊R中。
上⼀步操作之后,边
第5步:将边
上⼀步操作之后,边
第6步:将边加⼊R中。
上⼀步操作之后,边
问题⼀ 对图的所有边按照权值⼤⼩进⾏排序。
问题⼆ 将边添加到最⼩⽣成树中时,怎么样判断是否形成了回路。问题⼀很好解决,采⽤排序算法进⾏排序即可。问题⼆,处理⽅式是:记录顶点在"最⼩⽣成树"中的终点,顶点的终点是"在最⼩⽣成树中与它连通的最⼤顶点"。然后每次需要将⼀条边添加到最⼩⽣存树时,判断该边的两个顶点的终点是否重合,重合的话则会构成回路。
如何判断是否构成回路-举例说明(如图)
在将
(02) D的终点是F。
(03) E的终点是F。
(04) F的终点是F。
关于终点的说明:1. 就是将所有顶点按照从⼩到⼤的顺序排列好之后;某个顶点的终点就是"与它连通的最⼤顶点"。2. 因此,接下来,虽然
int matrix[][] = { /*A*//*B*//*C*//*D*//*E*//*F*//*G*/ /*A*/ { 0, 12, INF, INF, INF, 16, 14}, /*B*/ { 12, 0, 10, INF, INF, 7, INF}, /*C*/ { INF, 10, 0, 3, 5, 6, INF}, /*D*/ { INF, INF, 3, 0, 4, INF, INF}, /*E*/ { INF, INF, 5, 4, 0, 2, 8}, /*F*/ { 16, 7, 6, INF, 2, 0, 9}, /*G*/ { 14, INF, INF, INF, 8, 9, 0}};
//⼤家可以在去测试其它的邻接矩阵,结果都可以得到最⼩⽣成树.
//创建KruskalCase 对象实例 KruskalCase kruskalCase = new KruskalCase(vertexs, matrix); //输出构建的 (); l(); } public KruskalCase(char[] vertexs, int[][] matrix) { // TODO Auto-generated constructor stub //初始化顶点数和边的个数 int vlen = ;
//初始化顶点, 复制拷贝的⽅式 s = new char[vlen]; for(int i = 0; i < ; i++) { s[i] = vertexs[i]; }
//初始化边, 使⽤的是复制拷贝的⽅式 = new int[vlen][vlen]; for(int i = 0; i < vlen; i++) { for(int j= 0; j < vlen; j++) { [i][j] = matrix[i][j]; } } //统计边的条数 for(int i =0; i < vlen; i++) { for(int j = i+1; j < vlen; j++) { if([i][j] != INF) { edgeNum++; } } } } private void kruskal() { // TODO Auto-generated method stub int index=0;//表⽰最后结果数组的索引 int ends[]=new int[edgeNum];//⽤于保存"已有最⼩⽣成树" 中的每个顶点在最⼩⽣成树中的终点 //创建结果数组, 保存最后的最⼩⽣成树 Edata[] result=new Edata[edgeNum];
//获取图中 所有的边的集合 , ⼀共有12边 Edata[] edges = getEdges(); n("图的边的集合=" + ng(edges) + " 共"+ ); //12 //按照边的权值⼤⼩进⾏排序(从⼩到⼤) (edges);
//遍历edges 数组,将边添加到最⼩⽣成树中时,判断是准备加⼊的边否形成了回路,如果没有,就加⼊ rets, 否则不能加⼊ for(int i=0;i //获取p1这个顶点在已有最⼩⽣成树中的终点 int n=getEnd(ends,p1);//m = 4 //获取p2这个顶点在已有最⼩⽣成树中的终点 int m=getEnd(ends, p2);// n = 5 //是否构成回路 if(n!=m) {//没有构成回路 ends[n]=m; // 设置m 在"已有最⼩⽣成树"中的终点 result[index++]=edges[i];//有⼀条边加⼊到rets数组 } } // * @param ch 顶点的值,⽐如'A','B' * @return 返回ch顶点对应的下标,如果找不到,返回-1 */ private int getPosition(char ch) { for(int i = 0; i < ; i++) { if(vertexs[i] == ch) {//找到 return i; } } //找不到,返回-1 return -1; } /** * 功能: 获取图中边,放到EData[] 数组中,后⾯我们需要遍历该数组 * 是通过matrix 邻接矩阵来获取 * EData[] 形式 [['A','B', 12], ['B','F',7], .....] * @return */ private Edata[] getEdges() { // TODO Auto-generated method stub int index = 0; Edata[] edges = new Edata[edgeNum]; for(int i=0;i<;i++) { for(int j=i+1;j<;j++) { if(matrix[i][j]!=INF) { edges[index++] = new Edata(vertexs[i], vertexs[j], matrix[i][j]); } } } } return edges; } //打印邻接矩阵 private void print() { // TODO Auto-generated method stub n("邻接矩阵为: n"); for(int i = 0; i < ; i++) { for(int j=0; j < ; j++) { ("%12d", matrix[i][j]); } n();//换⾏ } } }//创建⼀个类EData ,它的对象实例就表⽰⼀条边class Edata implements Comparable }
2023年8月1日发(作者:)
克鲁斯卡尔算法(Kruskal)详解应⽤场景-公交站问题看⼀个应⽤场景和问题:1) 某城市新增 7 个站点 (A, B, C, D, E, F, G) ,现在需要修路把 7 个站点连通2) 各个站点的距离⽤边线表⽰ ( 权 ) ,⽐如 A – B 距离 12 公⾥3) 问:如何修路保证各个站点都能连通,并且总的修建公路总⾥程最短 ?
克鲁斯卡尔算法介绍1) 克鲁斯卡尔 (Kruskal) 算法,是⽤来求加权连通图的最⼩⽣成树的算法 。2) 基本思想 :按照权值从⼩到⼤的顺序选择 n-1 条边,并保证这 n-1 条边不构成回路3) 具体做法 :⾸先构造⼀个只含 n 个顶点的森林,然后依权值从⼩到⼤从连通⽹中选择边加⼊到森林中,并使森林中不产⽣回路,直⾄森林变成⼀棵树为⽌
克鲁斯卡尔算法图解说明以城市公交站问题来图解说明 克鲁斯卡尔算法的原理和步骤:在含有n个顶点的连通图中选择n-1条边,构成⼀棵极⼩连通⼦图,并使该连通⼦图中n-1条边上权值之和达到最⼩,则称其为连通⽹的最⼩⽣成树。
例如,对于如上图G4所⽰的连通⽹可以有多棵权值总和不相同的⽣成树。
克鲁斯卡尔算法图解以上图G4为例,来对克鲁斯卡尔进⾏演⽰(假设,⽤数组R保存最⼩⽣成树结果)。
第1步:将边
边
第2步:将边
上⼀步操作之后,边
第3步:将边
上⼀步操作之后,边
第4步:将边加⼊R中。
上⼀步操作之后,边
第5步:将边
上⼀步操作之后,边
第6步:将边加⼊R中。
上⼀步操作之后,边
问题⼀ 对图的所有边按照权值⼤⼩进⾏排序。
问题⼆ 将边添加到最⼩⽣成树中时,怎么样判断是否形成了回路。问题⼀很好解决,采⽤排序算法进⾏排序即可。问题⼆,处理⽅式是:记录顶点在"最⼩⽣成树"中的终点,顶点的终点是"在最⼩⽣成树中与它连通的最⼤顶点"。然后每次需要将⼀条边添加到最⼩⽣存树时,判断该边的两个顶点的终点是否重合,重合的话则会构成回路。
如何判断是否构成回路-举例说明(如图)
在将
(02) D的终点是F。
(03) E的终点是F。
(04) F的终点是F。
关于终点的说明:1. 就是将所有顶点按照从⼩到⼤的顺序排列好之后;某个顶点的终点就是"与它连通的最⼤顶点"。2. 因此,接下来,虽然
int matrix[][] = { /*A*//*B*//*C*//*D*//*E*//*F*//*G*/ /*A*/ { 0, 12, INF, INF, INF, 16, 14}, /*B*/ { 12, 0, 10, INF, INF, 7, INF}, /*C*/ { INF, 10, 0, 3, 5, 6, INF}, /*D*/ { INF, INF, 3, 0, 4, INF, INF}, /*E*/ { INF, INF, 5, 4, 0, 2, 8}, /*F*/ { 16, 7, 6, INF, 2, 0, 9}, /*G*/ { 14, INF, INF, INF, 8, 9, 0}};
//⼤家可以在去测试其它的邻接矩阵,结果都可以得到最⼩⽣成树.
//创建KruskalCase 对象实例 KruskalCase kruskalCase = new KruskalCase(vertexs, matrix); //输出构建的 (); l(); } public KruskalCase(char[] vertexs, int[][] matrix) { // TODO Auto-generated constructor stub //初始化顶点数和边的个数 int vlen = ;
//初始化顶点, 复制拷贝的⽅式 s = new char[vlen]; for(int i = 0; i < ; i++) { s[i] = vertexs[i]; }
//初始化边, 使⽤的是复制拷贝的⽅式 = new int[vlen][vlen]; for(int i = 0; i < vlen; i++) { for(int j= 0; j < vlen; j++) { [i][j] = matrix[i][j]; } } //统计边的条数 for(int i =0; i < vlen; i++) { for(int j = i+1; j < vlen; j++) { if([i][j] != INF) { edgeNum++; } } } } private void kruskal() { // TODO Auto-generated method stub int index=0;//表⽰最后结果数组的索引 int ends[]=new int[edgeNum];//⽤于保存"已有最⼩⽣成树" 中的每个顶点在最⼩⽣成树中的终点 //创建结果数组, 保存最后的最⼩⽣成树 Edata[] result=new Edata[edgeNum];
//获取图中 所有的边的集合 , ⼀共有12边 Edata[] edges = getEdges(); n("图的边的集合=" + ng(edges) + " 共"+ ); //12 //按照边的权值⼤⼩进⾏排序(从⼩到⼤) (edges);
//遍历edges 数组,将边添加到最⼩⽣成树中时,判断是准备加⼊的边否形成了回路,如果没有,就加⼊ rets, 否则不能加⼊ for(int i=0;i //获取p1这个顶点在已有最⼩⽣成树中的终点 int n=getEnd(ends,p1);//m = 4 //获取p2这个顶点在已有最⼩⽣成树中的终点 int m=getEnd(ends, p2);// n = 5 //是否构成回路 if(n!=m) {//没有构成回路 ends[n]=m; // 设置m 在"已有最⼩⽣成树"中的终点 result[index++]=edges[i];//有⼀条边加⼊到rets数组 } } // * @param ch 顶点的值,⽐如'A','B' * @return 返回ch顶点对应的下标,如果找不到,返回-1 */ private int getPosition(char ch) { for(int i = 0; i < ; i++) { if(vertexs[i] == ch) {//找到 return i; } } //找不到,返回-1 return -1; } /** * 功能: 获取图中边,放到EData[] 数组中,后⾯我们需要遍历该数组 * 是通过matrix 邻接矩阵来获取 * EData[] 形式 [['A','B', 12], ['B','F',7], .....] * @return */ private Edata[] getEdges() { // TODO Auto-generated method stub int index = 0; Edata[] edges = new Edata[edgeNum]; for(int i=0;i<;i++) { for(int j=i+1;j<;j++) { if(matrix[i][j]!=INF) { edges[index++] = new Edata(vertexs[i], vertexs[j], matrix[i][j]); } } } } return edges; } //打印邻接矩阵 private void print() { // TODO Auto-generated method stub n("邻接矩阵为: n"); for(int i = 0; i < ; i++) { for(int j=0; j < ; j++) { ("%12d", matrix[i][j]); } n();//换⾏ } } }//创建⼀个类EData ,它的对象实例就表⽰⼀条边class Edata implements Comparable }
发布评论