目录

1. 克鲁斯卡尔算法介绍

2. 公交站问题

2.1 克鲁斯卡尔算法图解

2.2 克鲁斯卡尔算法分析

2.3 如何判断是否构成回路

3. 代码实现


1. 克鲁斯卡尔算法介绍

1)克鲁斯卡尔(Kruskal)算法,是用来求加权连通图的最小生成树的算法。(最小生成树也可以通过普里姆算法生成,具体可参考算法其实很简单—普利姆算法)

2)基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路

3)具体做法:首先构造一一个只含n个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林中,并使森林中不产生回路,直至森林变成一棵树为止

2. 公交站问题

1)某城市新增7个站点(A,B,C,D,E,F,G), 现在需要修路把7个站点连通

2)各个站点的距离用边线表示(权),比如A-B距离12公里

3) 问:如何修路保证各个站点都能连通,并且总的修建公路总里程最短?

2.1 克鲁斯卡尔算法图解

第1步:将边<E,F>加入R中。

边<E,F>的权值最小,因此将它加入到最小生成树结果R中。

第2步:将边<C,D>加入R中。

上一步操作之后,边<C,D>的权值最小,因此将它加入到最小生成树结果R中。

第3步:将边<D,E>加入R中。

上一 步操作之后,边<D,E>的权值最小,因此将它加入到最小生成树结果R中。

第4步:将边<B,F>加入R中。

上一步操作之后,边<C,E>的权值最小,但<C,E>会和已有的边构成回路;因此,跳过边<C,E>。同理,跳过边<C,F>.将边<B,F>加入到最小生成树结果R中。

第5步:将边<E,G>加入R中。

上一步操作之后,边<E,G>的权值最小,因此将它加入到最小生成树结果R中。

第6步:将边<A,B>加入R中。

上一步操作之后,边<F,G>的权值最小,但<F,G>会和已有的边构成回路;因此,跳过边<F,G>。同理,跳过边<B,C>.将边<A,B>加入到最小生成树结果R中。

此时,最小生成树构造完成!它包括的边依次是: < <E,F> <C,D> <D,E><B,F> < <E,G> <A,B>.

2.2 克鲁斯卡尔算法分析

根据前面介绍的克鲁斯卡尔算法的基本思想和做法,我们能够了解到,克鲁斯卡尔算法重点需要解决的以下两个问题:

问题对图的所有边按照权值大小进行排序。

问题二将边添加到最小生成树中时,怎么样判断是否形成了回路。

问题一很好解决,采用排序算法进行排序即可。

问题二,处理方式是:记录顶点在"最小生成树"中的终点,顶点的终点是"在最小生成树中与它连通的最大顶点"。然后每次需要将一条边添加到最小生存树时,判断该边的两个顶点的终点是否重合,重合的话则会构成回路。

2.3 如何判断是否构成回路

在将<E,F> <C,D> <D,E>加入到最小生成树R中之后,这几条边的顶点就都有了终点:

(01) C的终点是F。

(02) D的终点是F。

(03)E的终点是F。

(04) F的终点是F。

关于终点的说明:

1)就是将所有顶点按照从小到大的顺序排列好之后;某个顶点的终点就是"与它连通的最大顶点"。

2)因此,接下来,虽然<C,E>是权值最小的边。但是C和E的终点都是F,即它们的终点相同,因此,将<C,E>加入最小生成树的话,会形成回路。这就是判断回路的方式。也就是说,我们加入的边的两个顶点不能都指向同一个终点,否则将构成回路。

3. 代码实现

package com.example.datastructureandalgorithm.kruska;import java.util.Arrays;
import java.util.Collections;/*** @author 浪子傑* @version 1.0* @date 2020/6/17*/
public class KruskaDemo {public static final int INF = Integer.MAX_VALUE;public static void main(String[] args) {char[] vertexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};//克鲁斯卡尔算法的邻接矩阵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}};Kruska kruska = new Kruska(vertexs, matrix);kruska.print();System.out.println(Arrays.toString(kruska.getEdges()));EData[] eDatas = kruska.getEdges();Collections.sort(Arrays.asList(eDatas));
//        kruska.sortEData(eDatas);System.out.println(Arrays.toString(eDatas));kruska.kruska();}
}class Kruska {private int edgeNum;private char[] vertexs;private int[][] matrix;public Kruska(char[] vertexs, int[][] matrix) {this.vertexs = vertexs;this.matrix = matrix;int length = vertexs.length;for (int i = 0; i < length; i++) {for (int j = i + 1; j < length; j++) {if (matrix[i][j] != KruskaDemo.INF) {edgeNum++;}}}}public void print() {for (int i = 0; i < vertexs.length; i++) {for (int j = 0; j < vertexs.length; j++) {System.out.printf("%12d", matrix[i][j]);}System.out.println();}}/*** 使用冒泡排序对eDatas进行排序** @param eDatas*/public void sortEData(EData[] eDatas) {for (int i = 0; i < eDatas.length - 1; i++) {for (int j = 0; j < eDatas.length - i - 1; j++) {if (eDatas[j + 1].weight < eDatas[j].weight) {EData temp = eDatas[j];eDatas[j] = eDatas[j + 1];eDatas[j + 1] = temp;}}}}/*** 查找ch对应点的下标** @param ch* @return*/public int getPosition(char ch) {for (int i = 0; i < vertexs.length; i++) {if (vertexs[i] == ch) {return i;}}return -1;}/*** 获取邻接矩阵转为的EData** @return*/public EData[] getEdges() {int index = 0;EData[] eDatas = new EData[edgeNum];for (int i = 0; i < vertexs.length; i++) {for (int j = i + 1; j < vertexs.length; j++) {if (matrix[i][j] != KruskaDemo.INF) {eDatas[index++] = new EData(vertexs[i], vertexs[j], matrix[i][j]);}}}return eDatas;}/*** 获取下标为i的顶点的终点,用于判断两个顶点的重点是否相同** @param ends 记录各个顶点的重点,动态生成的* @param i* @return*/public int getEnd(int[] ends, int i) {while (ends[i] != 0) {i = ends[i];}return i;}public void kruska() {// 表示结果数组的索引int index = 0;// 记录每个顶点的重点int[] ends = new int[edgeNum];// 最终返回的结果EData[] result = new EData[edgeNum];// 获取所有边的集合EData[] eDatas = getEdges();// 对eData进行排序sortEData(eDatas);for (int i = 0; i < edgeNum; i++) {// 获取开始顶点的位置int p1 = getPosition(eDatas[i].start);// 获取结束顶点的位置int p2 = getPosition(eDatas[i].end);// 获取终点位置int m = getEnd(ends, p1);int n = getEnd(ends, p2);// 当不相同时,说明没有形成回来if (m != n) {ends[m] = n;result[index++] = eDatas[i];}}for (int i = 0; i < index; i++) {System.out.println(result[i]);}}
}class EData implements Comparable<EData> {char start;char end;int weight;public EData(char start, char end, int weight) {this.start = start;this.end = end;this.weight = weight;}@Overridepublic String toString() {return "EData{" +"<" + start +", " + end +"> =" + weight +'}';}@Overridepublic int compareTo(EData o) {return this.weight - o.weight;}
}

算法其实很简单—克鲁斯卡尔算法相关推荐

  1. 常用算法(七)——克鲁斯卡尔算法

    克鲁斯卡尔算法 大纲目录 这里写目录标题 克鲁斯卡尔算法 一.应用场景-公交站问题 二.克鲁斯卡尔算法介绍 三.克鲁斯卡尔算法图解说明 四.源码 一.应用场景-公交站问题 某城市新增7个站点(A, B ...

  2. 常用十大算法(七)— 克鲁斯卡尔算法

    常用十大算法(七)- 克鲁斯卡尔算法 博客说明 文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢! 介绍 克鲁斯卡尔(Kruskal)算法,是 ...

  3. 贪心算法(Greedy Algorithm)最小生成树 克鲁斯卡尔算法(Kruskal#39;s algorithm)

    克鲁斯卡尔算法(Kruskal's algorithm)它既是古典最低的一个简单的了解生成树算法. 这充分反映了这一点贪心算法的精髓.该方法可以通常的图被表示.图选择这里借用Wikipedia在.非常 ...

  4. prim算法求最小生成树_克鲁斯卡尔算法(Kruskal算法)求最小生成树

    上一节介绍了求最小生成树之普里姆算法.该算法从顶点的角度为出发点,时间复杂度为O(n2),更适合与解决边的绸密度更高的连通网.本节所介绍的克鲁斯卡尔算法,从边的角度求网的最小生成树,时间复杂度为O(e ...

  5. 算法其实很简单—弗洛伊德(Floyd)算法

    目录 1.弗洛伊德(Floyd)算法介绍 2.弗洛伊德(Floyd)算法最佳应用-最短路径 3.弗洛伊德(Floyd)算法图解分析 3.1 弗洛伊德算法的步骤: 4.代码实现 1.弗洛伊德(Floyd ...

  6. 数据结构图之二(最小生成树--克鲁斯卡尔算法)

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

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

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

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

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

  9. 最小生成树之克鲁斯卡尔算法

    目录 前言 一.克鲁斯卡尔算法构造过程 二.算法实现 1.辅助结构体.数组 2.算法核心 3.排序函数 总结 前言 承接上文普里姆算法,这里的克鲁斯卡尔算法是解决最短联通路径的另一种算法,细节就不多概 ...

最新文章

  1. c++ 终止 超时_C++ 哪里超时了啊?
  2. 8 list切片_Python中14个切片操作,你常用哪几个?
  3. .NET Core跨平台的奥秘[下篇]:全新的布局
  4. Java压缩技术(七) TAR——Commons实现
  5. 加载gif动图_GIF生成神器——ScreenToGif
  6. 用命令实现Win7远程桌面关机和重启
  7. jQuery 版本viewer.js插件的结构分析与学习
  8. 一个很好用的JavaScript的文件上传插件plupload
  9. Linux下TCP网络服务器实现源代码3
  10. caffe框架deploy文件中
  11. leetcode加油站 Java
  12. idea出现outdated version提示框
  13. 加工制造业经销商渠道管理系统:共享上下游信息,加速交易效率
  14. php修改服务器ip地址,php修改服务器ip地址
  15. 书单 | 做数字化转型,离不开这10本书!
  16. Excel如何快速统计指定填充颜色的数据个数
  17. Caffe解惑:Caffe中是如何控制loss的
  18. Android开发-简介(一)
  19. Unable to negotiate with 100.9.70.30 port 29418: no matching key exchange method found
  20. 网易云信发布两大元宇宙解决方案,打响进军元宇宙第一枪

热门文章

  1. java spring mvc中类转换器
  2. 【数据挖掘 机器学习 】总结2:听徐老师讲课第二集
  3. 计算机专业英语单词mp3,[听单词] 计算机专业英语词汇音频62,计算机英语单词MP3...
  4. 金融科技之:小额贷款业务系统建设方案分享
  5. visual basic李天生第二章笔记
  6. 2021高考查询成绩南溪一中,烟花、撸串、喜报!宜宾高考查分夜晚有点“惊心动魄”~...
  7. html 图片渲染方式,仅用CSS实现图片渲染特效
  8. 1-LTE Network Architecture: Basic
  9. 京东双十一销售额突破2000亿
  10. 【shaderforge学习笔记】 Hue节点(色相节点)