算法背景:

图中顶点A,B,C,D,E,F,G七个顶点表示七个村庄,现要修路,使得任意两个村庄之间都有通路,即都能到达(可以不是直达),问怎样修路可以使修路的总里程最短?

思路:

将所有边都连接起来,肯定都有通路,但总里程数一定不是最小。应该使用尽量少的路线,并使每条路线的长度最小,便可保证总里程最小。

最小生成树:

修路问题的本质就是最小生成树问题,最小生成树:Minimum Cost Spanning Tree,简称MST。具体为:给定一个带权的无向图,如何选取生成树,使得所有边上权的总和最小。

最小生成树特征:

  • 有N个顶点,则N-1条边。
  • 包含了图的全部顶点。
  • N-1条边都在图中。

克鲁斯卡尔算法求最小生成树:

算法思路:

不同于普里姆算法的从点着手,克鲁斯卡尔算法以边为着手点,在所有的边的权值从小到大排序后,依次选边,使得在不构成回路的情况下形成最小生成树。

重点是对能否构成回路的判断:用一个end数组记录各顶点在"最小生成树"中的终点,顶点的终点是"在最小生成树中与它连通的最大顶点"(单个顶点的终点是自身)。然后每次需要将一条边添加到最小生存树时,判断该边的两个顶点的终点是否重合,重合的话则会构成回路。

判断回路核心代码:

//求某一顶点的终点,若end数组为空,则终点是自身,否则终点就是在end数组中不断往后直到为0时的点。
//例如:end{0,3,4,4,0},B顶点与D顶点相连,D顶点又与E顶点相连,所以B的终点就是E顶点
//而C顶点的终点也是E顶点,所以当B与C相连时,就会构成回路。
private int getEnd(int []end,int i) {while(end[i] != 0) {i = end[i];}return i;
}

kruskal核心代码:

算法分析:

克鲁斯卡尔算法的外层循环是对图的所有排好序的边进行遍历,可以对内层在求索引时进行优化,即边的类中直接保存两端点的索引,不保存两端点的“名”,但由于输出时需要输出顶点名,所以可将边类设置成内部类,便可利用索引在图类的属性vertex找出顶点名。

算法的内层主要是找顶点的终点,即克鲁斯卡尔算法只取决于边,与顶点无关。适合于图中的顶点很多,但连接的边不多的情况,即适用于稀疏图。

public void kruskal() {int []end = new int[vertex.size()];//保存终点的数组Edge []result = new Edge[vertex.size() - 1];//保存最小生成树Edge[] edgeAll = getEdgeAndSort();//得到图中排好序的边int j = 0;int sum = 0;//累积里程for(int i = 0; i < edgeAll.length;i++) {//遍历排好序的边int start = getIndex(edgeAll[i].start);//边的一个顶点索引int last = getIndex(edgeAll[i].end);//边的另一个顶点索引int m = getEnd(end, start);//求该索引动态连接的终点int n = getEnd(end, last);if(m != n) {end[m] = n;//在向生成树中加入顶点时更新开始一端的终点result[j++] = edgeAll[i];sum += edgeAll[i].weight;}}System.out.println();for(Edge data : result) {//输出生成树System.out.println(data);}System.out.println("需要修的总里程是" + sum + "米。");
}

java代码:

import java.util.*;public class Kruskal {public static void main(String[] args) {final int INF = Integer.MAX_VALUE;String []vertex = {"A","B","C","D","E","F","G"};int [][]edge = new int[][] {{INF,12,INF,INF,INF,16,14},{12,INF,10,INF,INF,7,INF},{7,10,INF,3,5,6,INF},{INF,INF,3,INF,4,INF,INF},{INF,INF,5,4,INF,2,8},{16,7,6,INF,2,INF,9},{14,INF,INF,INF,8,9,INF}};Graph graph = new Graph(vertex, edge);graph.printMatrix();graph.kruskal();}
}
class Graph{static final int INF = Integer.MAX_VALUE;ArrayList<String> vertex;int[][]edge;int numOfEdge;public Graph(String vertex[], int[][] edge) {int len = vertex.length;this.vertex = new ArrayList<String>(len);this.edge = new int [len][len];for(int i = 0;i < len;i++) {this.vertex.add(vertex[i]);for(int j = 0;j < len;j++) {this.edge[i][j] = edge[i][j];}}for(int i = 0; i < len;i++) {for(int j = i + 1;j < len;j++) {if(edge[i][j] != INF) {numOfEdge++;}}}}public void printMatrix() {System.out.println("邻接矩阵表示为:");for(int[] data : edge) {System.out.println(Arrays.toString(data));}}public Edge[] getEdgeAndSort() {int index = 0;Edge[] allEdge = new Edge[numOfEdge];for(int i = 0; i < vertex.size();i++) {for(int j = i + 1; j < vertex.size();j++) {if(edge[i][j] != INF) {allEdge[index++] = new Edge(vertex.get(i), vertex.get(j), edge[i][j]);}}}Arrays.sort(allEdge);return allEdge;}private int getIndex(String s) {for(int i = 0; i < vertex.size();i++) {if(vertex.get(i).equals(s)) {return i;}}return -1;}private int getEnd(int []end,int i) {while(end[i] != 0) {i = end[i];}return i;}public void kruskal() {int []end = new int[vertex.size()];Edge []result = new Edge[vertex.size() - 1];Edge[] edgeAll = getEdgeAndSort();int j = 0;int sum = 0;for(int i = 0; i < edgeAll.length;i++) {int start = getIndex(edgeAll[i].start);int last = getIndex(edgeAll[i].end);int m = getEnd(end, start);int n = getEnd(end, last);if(m != n) {end[m] = n;result[j++] = edgeAll[i];sum += edgeAll[i].weight;}}System.out.println();for(Edge data : result) {System.out.println(data);}System.out.println("需要修的总里程是" + sum + "米。");}
}class Edge implements Comparable<Edge>{String start;String end;int weight;public Edge(String start, String end, int weight) {this.start = start;this.end = end;this.weight = weight;}@Overridepublic String toString() {return "应连接:(" + start + "," + end + "),权值(距离)为:" + weight;}@Overridepublic int compareTo(Edge o) {return this.weight - o.weight;}
}

程序输出:

邻接矩阵表示为:
[2147483647, 12, 2147483647, 2147483647, 2147483647, 16, 14]
[12, 2147483647, 10, 2147483647, 2147483647, 7, 2147483647]
[7, 10, 2147483647, 3, 5, 6, 2147483647]
[2147483647, 2147483647, 3, 2147483647, 4, 2147483647, 2147483647]
[2147483647, 2147483647, 5, 4, 2147483647, 2, 8]
[16, 7, 6, 2147483647, 2, 2147483647, 9]
[14, 2147483647, 2147483647, 2147483647, 8, 9, 2147483647]应连接:(E,F),权值(距离)为:2
应连接:(C,D),权值(距离)为:3
应连接:(D,E),权值(距离)为:4
应连接:(B,F),权值(距离)为:7
应连接:(E,G),权值(距离)为:8
应连接:(A,B),权值(距离)为:12
需要修的总里程是36米。

优化后:(边类设置为内部类)

import java.util.*;public class Kruskal {public static void main(String[] args) {final int INF = Integer.MAX_VALUE;String []vertex = {"A","B","C","D","E","F","G"};int [][]edge = new int[][] {{INF,12,INF,INF,INF,16,14},{12,INF,10,INF,INF,7,INF},{7,10,INF,3,5,6,INF},{INF,INF,3,INF,4,INF,INF},{INF,INF,5,4,INF,2,8},{16,7,6,INF,2,INF,9},{14,INF,INF,INF,8,9,INF}};Graph graph = new Graph(vertex, edge);graph.printMatrix();graph.kruskal();}
}
class Graph{static final int INF = Integer.MAX_VALUE;ArrayList<String> vertex;int[][]edge;int numOfEdge;class Edge implements Comparable<Edge>{int start;int end;int weight;public Edge(int start, int end, int weight) {this.start = start;this.end = end;this.weight = weight;}@Overridepublic String toString() {return "应连接:(" + vertex.get(start) + "," + vertex.get(end) + "),权值(距离)为:" + weight;}@Overridepublic int compareTo(Edge o) {return this.weight - o.weight;}}public Graph(String vertex[], int[][] edge) {int len = vertex.length;this.vertex = new ArrayList<String>(len);this.edge = new int [len][len];for(int i = 0;i < len;i++) {this.vertex.add(vertex[i]);for(int j = 0;j < len;j++) {this.edge[i][j] = edge[i][j];}}for(int i = 0; i < len;i++) {for(int j = i + 1;j < len;j++) {if(edge[i][j] != INF) {numOfEdge++;}}}}public void printMatrix() {System.out.println("邻接矩阵表示为:");for(int[] data : edge) {System.out.println(Arrays.toString(data));}}public Edge[] getEdgeAndSort() {int index = 0;Edge[] allEdge = new Edge[numOfEdge];for(int i = 0; i < vertex.size();i++) {for(int j = i + 1; j < vertex.size();j++) {if(edge[i][j] != INF) {allEdge[index++] = new Edge(i, j, edge[i][j]);}}}Arrays.sort(allEdge);return allEdge;}private int getEnd(int []end,int i) {while(end[i] != 0) {i = end[i];}return i;}public void kruskal() {int []end = new int[vertex.size()];Edge []result = new Edge[vertex.size() - 1];Edge[] edgeAll = getEdgeAndSort();int j = 0;int sum = 0;for(int i = 0; i < edgeAll.length;i++) {int start = edgeAll[i].start;int last = edgeAll[i].end;int m = getEnd(end, start);int n = getEnd(end, last);if(m != n) {end[m] = n;result[j++] = edgeAll[i];sum += edgeAll[i].weight;}}System.out.println();for(Edge data : result) {System.out.println(data);}System.out.println("需要修的总里程是" + sum + "米。");}
}

克鲁斯卡尔算法(kruskal)相关推荐

  1. 无向图的最小生成树(克鲁斯卡尔算法 Kruskal)

    引子: 克鲁斯卡尔算法的作用是:构建图的最小生成树. 克鲁斯卡尔算法 Kruskal的构造过程: 1.初始化图:n个顶点,n个连通分量(如果两个顶点的连通分量相同,表示两点在同一个连通图中).把所有的 ...

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

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

  3. Java普利姆算法(Prim)与克鲁斯卡尔算法(Kruskal)

    1.Java普利姆算法(Prim)与克鲁斯卡尔算法(Kruskal) 普利姆算法(Prim)与克鲁斯卡尔算法(Kruskal)求**最小生成树(极小连通子图)**的算法 1.1普利姆算法(Prim) ...

  4. 数据结构——最小生成树之克鲁斯卡尔算法(Kruskal)

    最小生成树算法 prime算法和克鲁斯卡尔算法 克鲁斯卡尔算法 思路 优先队列+并查集 Kuskal算法 [算法简介]:上一篇中的Prime算法是一种"加点式的算法",而Kuska ...

  5. 数据结构与算法-克鲁斯卡尔算法(Kruskal) | 尚硅谷韩顺平

    提出问题 基本介绍 克鲁斯卡尔(Kruskal)算法,求加权连通图最小生成树的算法 基本思想:按权值从小到大顺序选择n-1条边,保证n-1条边不够成回路 具体做法:先构造一个只有n顶点的森林,然后按权 ...

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

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

  7. kruskal算法java_克鲁斯卡尔算法(Kruskal)的java实现

    下面是我对软件工程教程里面的克鲁斯卡尔算法的实现,发现在网是很少有网友贴出,为了方便大家查询,所以贴出来了,还希望大家能多指点. package Test; import java.io.Buffer ...

  8. 最小生成树练习1(克鲁斯卡尔算法Kruskal)

    今天刷一下水题练手入门,明天继续. poj1861 Network(最小生成树)新手入门题. 题意:输出连接方案中最长的单根网线长度(必须使这个值是所有方案中最小的),然后输出方案. 题解:本题没有直 ...

  9. 【数据结构基础整理】图--06:克鲁斯卡尔算法详解

    详解最小生成树中的克鲁斯卡尔算法 0x01.关于克鲁斯卡尔算法 Kruskal算法是一种用来查找最小生成树的算法,由Joseph Kruskal在1956年发表.克鲁斯卡尔算法主要针对边集数组展开. ...

  10. 最小生成树之克鲁斯卡尔(Kruskal)算法

    学习最小生成树算法之前我们先来了解下 下面这些概念: 树(Tree):如果一个无向连通图中不存在回路,则这种图称为树. 生成树 (Spanning Tree):无向连通图G的一个子图如果是一颗包含G的 ...

最新文章

  1. 在 App Store 三年學到的 13 件事(下)
  2. QT安装由问题的,安装后发现有些控件标签名显示不了
  3. 扎克伯格凌晨放大招,说几句话能造世界的那种
  4. NYOJ 5767 装背包
  5. linux 验证邮箱账号,linux邮件服务器的身份验证(sasl)
  6. 如何打开Tango的ADF文件?
  7. 未找到要求的 from 关键字_性能优化|这恐怕是解释Explain关键字最全的一篇文章
  8. OC开发_Storyboard——MapKit
  9. UE4之镜头移动到某个actor
  10. 【问题】ajax两种传递id值方式的区别
  11. 来自吉普赛人祖传的神奇读心术.它能测算出你的内心感应
  12. windows VM12虚拟机安装苹果系统(Mac OX 10.11)
  13. mysql注入转义绕过_SQL注入防御绕过——二次注入
  14. 面试题 | ISP 图像处理算法工程师
  15. 放弃OneNote,拥抱 Obsidian
  16. Django 2.1.7 项目技巧 - 创建apps应用目录归纳所有应用
  17. hdu 1109 Run Away
  18. 基于安卓的校园跳蚤市场app
  19. 浅谈CTF中各种花式绕过的小trick
  20. 广义势能函数和带电粒子在电磁场中的运动

热门文章

  1. jointjs Element
  2. windows xp安装驱动时提示驱动未通过微软数字签名
  3. restful 简单理解
  4. Educational Codeforces Round 138 (A-E)题解
  5. MTA考java_27.8.5 imsimta 计数器
  6. NSGA II实例讲解
  7. JavaScript 中内存泄漏的几种情况
  8. auto.js对接联众的一个实例
  9. 12位密码最靠谱 破解需用17134年
  10. 超融合火了这么多年,为何市场份额还是这么小?