克鲁斯卡尔(Kruskal)算法(K算法):公交站问题

2024-06-21 02:38

本文主要是介绍克鲁斯卡尔(Kruskal)算法(K算法):公交站问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1,应用场景—公交站问题

在这里插入图片描述

  • 某城市从新增的7个站点(A,B,C,D,E,F,G),现在需要把7个站点联通
  • 各个站点的距离用边权表示,比如A-B为12公里
  • 如何修路保证各个站点都能走通,并距离最短
  • 从图和问题可以看出,克鲁斯卡尔算法与普里姆算法解决的问题完成一致,只是解决问题的方式不同

2,克鲁斯卡尔算法介绍

  • 克鲁斯卡尔算法,是用来求加权连通图的最小生成树的算法
  • 基本算法思想:按照边权值大小从小到大的顺序选取n - 1条边,并保证这n - 1条边不构成回路
  • 回路的判断标准是连接边的两个顶点的终点重合

2.1,算法图解

  1. 以应用场景中的左图为例

  2. 第一步,取最小的边,即<E,F>,权值为2
    在这里插入图片描述

  3. 第二步,继续取最小的边,即<C,D>,权值为3
    在这里插入图片描述

  4. 第三步,继续取<D,E>,此处注意,构成回路的标准是顶点的终点不能一致,不是按照顶点的访问记录判断
    在这里插入图片描述

  5. 紧接着,取最小的边<C,E>,此处注意,<C,E>构成了回路;因为将<E,F>,<C,D>,<D,E>加入到最小生成树中后,这几个边的顶点<C,D,E,F>就都了各自的终点F,此时再连接<C,E>时,<C,E>的终点都为F,终点重合,则构成了回路,不能构建

  6. 按照第一步到第五步的逻辑,依次类推,则最后的结果如下:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RdhJKpLa-1595081311522)(E:\gitrepository\study\note\image\dataStructure\1594454750120.png)]

  7. 此时,最小生成树构建完成,最后的结果是<E,F>,<C,D>,<D,E>,<B,F>,<E,G>,<A,B>

3,代码实现

package com.self.datastructure.algorithm.kruskal;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** 克鲁斯卡尔算法* * 克鲁斯卡尔算法与Prim算法解决问题完全一致, 只是解决问题的方式不同* * 不同于Prim算法以点为基本单位, 克鲁斯卡尔以边为基本单位* * 先构建问题图表, 构建顶点, 并从中读取边的集合(注意不要读取两份)* * 然后对边按大小进行升序排列* * 遍历边的集合, 依次取出最小的边, 参与最小生成树的生成* * 分别从顶点-终点的记录数组中取出该边对应两个顶点的终点* * 如果终点重合说明构成了回路, 则不能构建* * 终点不重合, 说明还没有连接, 则继续构建* * 边集合遍历完成后, 整个最小生成树构建也随之完成* * 注意: 此处不能通过顶点已经访问来统计, 比如ABCD四个顶点, AB构成, CD构成, 此时ABCD已经全部访问, 但是不连通* @author pj_zhang* @create 2020-07-11 12:12**/
public class Kruskal {private final static int NOT_CONN = Integer.MAX_VALUE;public static void main(String[] args) {// 顶点集合char[] lstVertex = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};// 连接关系int[][] vertexMap = {{0, 12, NOT_CONN, NOT_CONN, NOT_CONN, 16, 14},{12, 0, 10, NOT_CONN, NOT_CONN, 7, NOT_CONN},{NOT_CONN, 10, 0, 3, 5, 6, NOT_CONN},{NOT_CONN, NOT_CONN, 3, 0, 4, NOT_CONN, NOT_CONN},{NOT_CONN, NOT_CONN, 5, 4, 0, 2, 8},{16, 7, 6, NOT_CONN, 2, 0, 9},{14, NOT_CONN, NOT_CONN, NOT_CONN, 8, 9, 0}};// 构建图MyGraph myGraph = new MyGraph(lstVertex, vertexMap);// 进行克鲁斯卡尔计算MyEdge[] result = kruskal(myGraph);System.out.println("最终结果如下: ");for (MyEdge myEdge : result) {System.out.println(myEdge);}}/*** 进行克鲁斯卡尔算法计算* @param myGraph 图表* @return 返回最终的连接关系*/private static MyEdge[] kruskal(MyGraph myGraph) {// 结果集, 边的数量为顶点数量-1MyEdge[] result = new MyEdge[myGraph.getLstVertex().length - 1];int index = 0; // 记录下标位置// 顶点的连接终点集合, 初始化为0int[] endArr = new int[myGraph.getLstVertex().length];// 获取边集合MyEdge[] lstEdges = myGraph.getLstEdges();// 对边按权值从小到大进行排序sortEdges(lstEdges);// 对边集合进行遍历, 从最小开始取边进行最小生成树构建for (MyEdge myEdge : lstEdges) {// 获取边开始和结束的顶点char startVertex = myEdge.getStart();char endVertex = myEdge.getEnd();// 获取顶点对应的下标int startIndex = getVertexIndex(myGraph, startVertex);int endIndex = getVertexIndex(myGraph, endVertex);// 获取顶点连接串的终点, 避免构成回路int startEnd = getEndIndex(endArr, startIndex);int endEnd = getEndIndex(endArr, endIndex);// 如果终点值不重合, 说明不会构成回路, 则进行连接if (startEnd != endEnd) {// 对终点的终点进行延伸endArr[startEnd] = endEnd;// 记录边result[index++] = myEdge;}}System.out.println("终点数组: " + Arrays.toString(endArr));return result;}/*** 获取顶点的终点索引* @param endArr 终点记录数组* @param index 当前顶点下标* @return 终点下标*/private static int getEndIndex(int[] endArr, int index) {// 如果当前顶点存在终点, 则继续去找终点的终点// 找到最终点, 最终返回该索引while (endArr[index] != 0) {index = endArr[index];}// 如果当前顶点的终点为0, 表示顶点的终点就是它自己, 直接返回即可return index;}/*** 获取顶点对应的下标* @param myGraph 图* @param vertex 顶点* @return*/private static int getVertexIndex(MyGraph myGraph, char vertex) {for (int i = 0; i < myGraph.getLstVertex().length; i++) {if (myGraph.getLstVertex()[i] == vertex) {return i;}}return -1;}/*** 对边按权值进行排序* @param lstEdges*/private static void sortEdges(MyEdge[] lstEdges) {for (int i = 0; i < lstEdges.length; i++) {for (int j = 0; j < lstEdges.length - 1 - i; j++) {if (lstEdges[j].getWeight() > lstEdges[j + 1].getWeight()) {MyEdge temp = lstEdges[j];lstEdges[j] = lstEdges[j + 1];lstEdges[j + 1] = temp;}}}}/*** 构建图表*/@Getterstatic class MyGraph {/*** 顶点数量*/private int vertexCount;/*** 顶点列表*/private char[] lstVertex;/*** 顶点图*/private int[][] vertexMap;/*** 顶点的边集合*/private MyEdge[] lstEdges;public MyGraph(char[] lstVertex, int[][] vertexMap) {this.vertexCount = lstVertex.length;this.lstVertex = lstVertex;this.vertexMap = vertexMap;// 记录边, 按顺序读取, 保证顺序List<MyEdge> lstData = new ArrayList<>(10);for (int i = 0; i < vertexCount; i++) {// 从下一位开始读, 保证不会生成重复的边for (int j = i + 1; j < vertexCount; j++) {// 如果连接, 则进行统计if (vertexMap[i][j] != NOT_CONN) {lstData.add(new MyEdge(lstVertex[i], lstVertex[j], vertexMap[i][j]));}}}lstEdges = new MyEdge[lstData.size()];for (int i = 0; i < lstData.size(); i++) {lstEdges[i] = lstData.get(i);}}}/*** 边对象*/@Data@AllArgsConstructorstatic class MyEdge {/*** 起点*/private char start;/*** 终点*/private char end;/*** 权重*/private int weight;}}

这篇关于克鲁斯卡尔(Kruskal)算法(K算法):公交站问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1079983

相关文章

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

如何解决mysql出现Incorrect string value for column ‘表项‘ at row 1错误问题

《如何解决mysql出现Incorrectstringvalueforcolumn‘表项‘atrow1错误问题》:本文主要介绍如何解决mysql出现Incorrectstringv... 目录mysql出现Incorrect string value for column ‘表项‘ at row 1错误报错

如何解决Spring MVC中响应乱码问题

《如何解决SpringMVC中响应乱码问题》:本文主要介绍如何解决SpringMVC中响应乱码问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring MVC最新响应中乱码解决方式以前的解决办法这是比较通用的一种方法总结Spring MVC最新响应中乱码解

pip无法安装osgeo失败的问题解决

《pip无法安装osgeo失败的问题解决》本文主要介绍了pip无法安装osgeo失败的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 进入官方提供的扩展包下载网站寻找版本适配的whl文件注意:要选择cp(python版本)和你py

解决Java中基于GeoTools的Shapefile读取乱码的问题

《解决Java中基于GeoTools的Shapefile读取乱码的问题》本文主要讨论了在使用Java编程语言进行地理信息数据解析时遇到的Shapefile属性信息乱码问题,以及根据不同的编码设置进行属... 目录前言1、Shapefile属性字段编码的情况:一、Shp文件常见的字符集编码1、System编码

Spring MVC使用视图解析的问题解读

《SpringMVC使用视图解析的问题解读》:本文主要介绍SpringMVC使用视图解析的问题解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring MVC使用视图解析1. 会使用视图解析的情况2. 不会使用视图解析的情况总结Spring MVC使用视图

Redis解决缓存击穿问题的两种方法

《Redis解决缓存击穿问题的两种方法》缓存击穿问题也叫热点Key问题,就是⼀个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击,本文给大家介绍了Re... 目录引言解决办法互斥锁(强一致,性能差)逻辑过期(高可用,性能优)设计逻辑过期时间引言缓存击穿:给