实验一-最小生成树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条边不构成回路. 具体做法:首先构造一个 ...
随机推荐
- 笔记-[ZJOI2014]力
[ZJOI2014]力 \[\begin{split} E_j=&\sum_{i=1}^{j-1}\frac{q_i}{(i-j)^2}-\sum_{i=j+1}^{n}\frac{q_i}{ ...
- jwt 简单基本使用加密解密
import jwt # 加密 encode_jwt=jwt.encode({'uid':'123'},'密钥123',algorithm='HS256') print(encode_jwt) # 解 ...
- vue单页面应用刷新网页后vuex的state数据丢失的解决办法
第一种方案 首先将数据保存在vuex的store中,同时将这些信息也保存在sessionStorage中.这里需要注意的是vuex中的变量是响应式的,而sessionStorage不是,当你改变vue ...
- sqli-labs第5关布尔盲注pyhton脚本
import requests import os #此函数先判断数据库长度 def length(url,str): num = 1 while True: str_num = '%d' %num ...
- PHPCMS V9.6.3的后台漏洞分析
PHPCMS V9.6.3后台的漏洞分析 1.利用文件包含创建任意文件getshell 漏洞文件:\phpcmsv9\phpcms\modules\block\block_admin.php 漏洞产生 ...
- Kali Linux破解wifi密码(无须外置网卡)
环境准备: 方式一(选择该方式):Kali Linux.笔记本一台.U盘(至少8G) 方式二:Kali Linux.外置网卡.笔记本一台.VM 特别说明,主要是使用方式一进行破解,如果有外置网 ...
- 第 13 章 StringTable详解
目录 第 13 章 StringTable 1.String 的基本特性 1.1.String 概述 1.2.String 的基本特征 1.3.String 的底层结构 2.String 的内存分配 ...
- 超简单的 Docker部署 SpringBoot项目 步骤
很久之前就用过,一直没有好好写篇博客,今天就总结一下 创建一个 SpringBoot项目 创建一个SpringBoot项目并打成jar包,结构如图 编写 Dockerfile文件 FROM java: ...
- RabbiMQ重新安装会遇到的错误-SpiritMark
这里只做安装过程中遇到错误的介绍,不喜勿喷,如果对您有帮助右上角关注一下,是对我最大的肯定 重新安装的注意事项: 先卸载RabbitMQ,后卸载Erlang RabbitMQ卸载,选择uninstal ...
- 图解JanusGraph系列 - 关于JanusGraph图数据批量快速导入的方案和想法(bulk load data)
大家好,我是洋仔,JanusGraph图解系列文章,实时更新~ 图数据库文章总目录: 整理所有图相关文章,请移步(超链):图数据库系列-文章总目录 源码分析相关可查看github(码文不易,求个sta ...