实验一-最小生成树Kruskal算法
实验名称
最小生成树算法-Kruskal算法
实验目的
1.掌握并查集的合并优化和查询优化;
2.掌握Kruskal算法。
3.能够针对实际问题,能够正确选择贪心策略。
4.能够针对选择的贪心策略,证明算法的正确性。
5.能够根据贪心策略,正确编码。
6.能够正确分析算法的时间复杂度和空间复杂度
实验内容
采用Kruskal算法生成最小生成树,并采用并查集的合并优化和查询优化。
实验环境
操作系统:win 10;
编程语言:Java,JDK1.8;
开发工具:IDEA;
实验过程
算法简介
Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表。用来解决同样问题的还有Prim算法和Boruvka算法等。三种算法都是贪婪算法的应用。和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效。
算法步骤
Kruskal算法又称加边算法,初始最小生成树的边数是0,每次迭代都从边的集合中选取最小代价的边,我们称他为最小代价边,加入到最小生成树的边集合中。
- 将图中所有的边按照权值大小从小到大排序。
- 把N个顶点看成独立的森林。
- 从排好序的边集合中取出当前最小的边,所选连接的顶点是v,w,如果两个顶点添加到最小生成树中后不会构成环,那就加入,反之跳过本次循环。
- 重复步骤三,直到所有顶点添加完成或者最小生成树的边的数量=顶点数-1。
代码实现
代码总体分为三部分,分别是最小生成树的生成,并查集的构建,对边权值的处理。
并查集用来快速判断两个元素加入到生成树中会不会构成环,如果两个元素加入到并查集中是属于同一个分组,代表构成环,所以直接continue;反之,将这条边加到独立的最小生成树中,边数++,并更新总权值,如果边数==顶点数-1;退出循环。权值处理主要是通过排序将边的权值按照从小到大的顺序添加到最小生成树中,排序可以选择内置的快排或者堆排。
package org.qianyan.algorithm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class Kruskal {
/**
* 最小生成树的权值之和
*/
private int mstCost;
//获取最小生成树的总权值
public int getMstCost() {
return mstCost;
}
/**
* 最小生成树的边的列表
*/
private List<int[]> mst;
//获取最小生成树的边的集合
public List<int[]> getMst() {
return mst;
}
/**
* @param V 总结点数
* @param edges 每条边的定义:[起始点, 终点, 权值]
*/
public Kruskal(int V, int[][] edges) {
//E代表一共多少条边
int E = edges.length;
//边数小于顶点数是构不成最小生成树
if (E < V - 1) {
throw new IllegalArgumentException("参数错误");
}
mst = new ArrayList<>(E - 1);
// 体现了贪心的思想,从权值最小的边开始考虑 这里采用了排序的思想,来获取最小边
Arrays.sort(edges, Comparator.comparingInt(o -> o[2]));
//创建一个并查集
UnionFind unionFind = new UnionFind(V);
// 当前找到了多少条边
int count = 0;
for (int[] edge : edges) {
// 如果形成了环,就继续考虑下一条边
if (unionFind.isConnected(edge[0], edge[1])) {
continue;
}
//如果没有形成环,将两个顶点连接在一个集合
unionFind.union(edge[0], edge[1]);
//加上这条边的权值
this.mstCost += edge[2];
//最小生成树加上这条边
mst.add(new int[]{edge[0], edge[1], edge[2]});
//当前最小生成树的边数++
count++;
//循环结束条件,v个顶点有v-1条边构成最小生成树
if (count == V - 1) {
break;
}
}
}
/**
* 并查集
*/
private class UnionFind {
//每个并查集中的节点都有一个“大哥”
private int[] parent;
//并查集中的分组数
private int count;
//N代表并查集中节点的总数
private int N;
public UnionFind(int N) {
this.N = N;
this.count = N;
this.parent = new int[N];
for (int i = 0; i < N; i++) {
//各个节点的初始父节点都是他们自己
parent[i] = i;
}
}
/**
* 查找指定元素在哪一个分组,也就是节点跟随最终的“大哥”是谁
*
* @param x
* @return
*/
public int find(int x) {
while (x != parent[x]) {
x = parent[x];
}
return x;
}
/**
* 合并两个元素所在的分组,将两个顶点的大哥统一
*
* @param x
* @param y
*/
public void union(int x, int y) {
//找到他们各自的祖节点,
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY) {
return;
}
//合并之后分组总数--
parent[rootX] = rootY;
count--;
}
public int getCount() {
return count;
}
//判断是不是同一个分组,也就是两个元素是不是同一个大哥的小弟
public boolean isConnected(int x, int y) {
return find(x) == find(y);
}
}
public static void main(String[] args) {
int N = 7;
//edges[0] 表示起始顶点,edges[1]表示终止定点,edges[2]代表这条边的权值
int[][] edges = {{0, 1, 4},
{0, 5, 8},
{1, 2, 8},
{1, 5, 11},
{2, 3, 3},
{2, 6, 2},
{3, 4, 3},
{4, 5, 8},
{4, 6, 6},
{5, 6, 7},
};
//顶点是0-6,一共10条边
Kruskal kruskal = new Kruskal(N, edges);
//总权值
int mstCost = kruskal.getMstCost();
System.out.println("最小生成树的权值之和:" + mstCost);
List<int[]> mst = kruskal.getMst();
System.out.println("最小生成树的边的列表:");
for (int[] edge : mst) {
System.out.println("[起始顶点:" + edge[0] + "-终止顶点" + edge[1] + "]" + ",权值:" + edge[2]);
}
}
}

复杂度分析
并查集查找空间复杂度是O(n),合并和判断是不是同一个集合时间复杂度是O(1);
Kruskal算法的时间复杂度:O(E log E),这里 E 是图的边数;
空间复杂度:O(V),这里 V 是图的顶点数,并查集需要 V 长度的数组空间。
实验一-最小生成树Kruskal算法的更多相关文章
- 【转】最小生成树——Kruskal算法
[转]最小生成树--Kruskal算法 标签(空格分隔): 算法 本文是转载,原文在最小生成树-Prim算法和Kruskal算法,因为复试的时候只用到Kruskal算法即可,故这里不再涉及Prim算法 ...
- 最小生成树——kruskal算法
kruskal和prim都是解决最小生成树问题,都是选取最小边,但kruskal是通过对所有边按从小到大的顺序排过一次序之后,配合并查集实现的.我们取出一条边,判断如果它的始点和终点属于同一棵树,那么 ...
- 最小生成树Kruskal算法
Kruskal算法就是把图中的所有边权值排序,然后从最小的边权值开始查找,连接图中的点,当该边的权值较小,但是连接在途中后会形成回路时就舍弃该边,寻找下一边,以此类推,假设有n个点,则只需要查找n-1 ...
- 最小生成树------Kruskal算法
Kruskal最小生成树算法的概略描述:1 T=Φ:2 while(T的边少于n-1条) {3 从E中选取一条最小成本的边(v,w):4 从E中删去(v,w):5 if((v,w)在T中不生成环) { ...
- 求最小生成树——Kruskal算法
给定一个带权值的无向图,要求权值之和最小的生成树,常用的算法有Kruskal算法和Prim算法.这篇文章先介绍Kruskal算法. Kruskal算法的基本思想:先将所有边按权值从小到大排序,然后按顺 ...
- 最小生成树 kruskal算法&prim算法
(先更新到这,后面有时间再补,嘤嘤嘤) 今天给大家简单的讲一下最小生成树的问题吧!(ps:本人目前还比较菜,所以最小生成树最后的结果只能输出最小的权值,不能打印最小生成树的路径) 本Tianc在刚学的 ...
- 算法实践--最小生成树(Kruskal算法)
什么是最小生成树(Minimum Spanning Tree) 每两个端点之间的边都有一个权重值,最小生成树是这些边的一个子集.这些边可以将所有端点连到一起,且总的权重最小 下图所示的例子,最小生成树 ...
- 模板——最小生成树kruskal算法+并查集数据结构
并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每 ...
- 数据结构之最小生成树Kruskal算法
1. 克鲁斯卡算法介绍 克鲁斯卡尔(Kruskal)算法,是用来求加权连通图的最小生成树的算法. 基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路. 具体做法:首先构造一个 ...
随机推荐
- Tensorflow学习笔记No.10
多输出模型 使用函数式API构建多输出模型完成多标签分类任务. 数据集下载链接:https://pan.baidu.com/s/1JtKt7KCR2lEqAirjIXzvgg 提取码:2kbc 1.读 ...
- kafka命令及启动
默认内网访问,要在外网访问的话,需要在修改config/server.properties中的配置 将listeners和advertised.listeners的值用主机名进行替换,在外用使用jav ...
- 我的第一次shell
我的第一次shell 最近我们的项目需要进行优化,整体架构进行改造. 然后我们红超哥就看我骨骼惊奇,说小伙子你想不想当做掌门人呀.(我说不想哈哈) 想不想也没用了,红超哥说我们现在的架构有所改变,需要 ...
- 云小课 | 需求任务还未分解,该咋整!项目管理Scrum项目工作分解的心酸谁能知?
温馨提醒:本文约3000字,需要阅读5分钟,共分为8个部分,建议分段阅读! 软件开发过程中,从产品概念形成到产品规划.往往要做详细的需求分析和项目规划等,因此,选对一款项目管理工具对开发者就显得尤为重 ...
- oracle DG查看延时时间
oracle DG查看延时时间 SQL> select value from v$dataguard_stats where name='apply lag'; 例如: SQL> sele ...
- 如何配置nginx达到只允许域名访问网址,禁止ip访问的效果
需求:接入阿里云的waf对网站进行防护,但是如果直接通过IP地址访问网站即可绕过阿里云waf,于是希望禁止通过ip访问网站 修改nginx配置文件 在server段里插入如下内容即可 if ($hos ...
- vscode php转到定义
点击再settings.json 中编辑 添加这一行,内容为php的安装路径
- yii\filters\AccessControl 访问权限控制
Class yii\filters\AccessControl 所有类 | 属性 | 方法 继承 yii\filters\AccessControl » yii\base\ActionFilter ...
- 在matlab 画箭头
[转载]在matlab 画箭头 原文地址:在matlab 画箭头作者:纯情小郎君 完整见链接http://www.mathworks.com/matlabcentral/fx_files/14056/ ...
- RPC 核心,万变不离其宗
微信搜 「yes的练级攻略」干货满满,不然来掐我,回复[123]一份20W字的算法刷题笔记等你来领. 个人文章汇总:https://github.com/yessimida/yes 欢迎 star ! ...