实验名称

最小生成树算法-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,每次迭代都从边的集合中选取最小代价的边,我们称他为最小代价边,加入到最小生成树的边集合中。

  1. 将图中所有的边按照权值大小从小到大排序。
  2. 把N个顶点看成独立的森林。
  3. 从排好序的边集合中取出当前最小的边,所选连接的顶点是v,w,如果两个顶点添加到最小生成树中后不会构成环,那就加入,反之跳过本次循环。
  4. 重复步骤三,直到所有顶点添加完成或者最小生成树的边的数量=顶点数-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算法的更多相关文章

  1. 【转】最小生成树——Kruskal算法

    [转]最小生成树--Kruskal算法 标签(空格分隔): 算法 本文是转载,原文在最小生成树-Prim算法和Kruskal算法,因为复试的时候只用到Kruskal算法即可,故这里不再涉及Prim算法 ...

  2. 最小生成树——kruskal算法

    kruskal和prim都是解决最小生成树问题,都是选取最小边,但kruskal是通过对所有边按从小到大的顺序排过一次序之后,配合并查集实现的.我们取出一条边,判断如果它的始点和终点属于同一棵树,那么 ...

  3. 最小生成树Kruskal算法

    Kruskal算法就是把图中的所有边权值排序,然后从最小的边权值开始查找,连接图中的点,当该边的权值较小,但是连接在途中后会形成回路时就舍弃该边,寻找下一边,以此类推,假设有n个点,则只需要查找n-1 ...

  4. 最小生成树------Kruskal算法

    Kruskal最小生成树算法的概略描述:1 T=Φ:2 while(T的边少于n-1条) {3 从E中选取一条最小成本的边(v,w):4 从E中删去(v,w):5 if((v,w)在T中不生成环) { ...

  5. 求最小生成树——Kruskal算法

    给定一个带权值的无向图,要求权值之和最小的生成树,常用的算法有Kruskal算法和Prim算法.这篇文章先介绍Kruskal算法. Kruskal算法的基本思想:先将所有边按权值从小到大排序,然后按顺 ...

  6. 最小生成树 kruskal算法&prim算法

    (先更新到这,后面有时间再补,嘤嘤嘤) 今天给大家简单的讲一下最小生成树的问题吧!(ps:本人目前还比较菜,所以最小生成树最后的结果只能输出最小的权值,不能打印最小生成树的路径) 本Tianc在刚学的 ...

  7. 算法实践--最小生成树(Kruskal算法)

    什么是最小生成树(Minimum Spanning Tree) 每两个端点之间的边都有一个权重值,最小生成树是这些边的一个子集.这些边可以将所有端点连到一起,且总的权重最小 下图所示的例子,最小生成树 ...

  8. 模板——最小生成树kruskal算法+并查集数据结构

    并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每 ...

  9. 数据结构之最小生成树Kruskal算法

    1. 克鲁斯卡算法介绍 克鲁斯卡尔(Kruskal)算法,是用来求加权连通图的最小生成树的算法. 基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路. 具体做法:首先构造一个 ...

随机推荐

  1. #2020征文-开发板#SYS_RUN()和MODULE_INIT()之间的那些事

    接触鸿蒙设备开发有一段时间了,也是时候好好挖一挖鸿蒙设备程序的启动流程了. 破冰问题:鸿蒙设备程序从哪里开始运行的? 相信大家都已经非常清楚了,鸿蒙设备程序需要指定入口函数,具体表现在代码层面就是通过 ...

  2. Clickhouse 在大数据分析平台 - 留存分析上的应用

    导语 | 本文实践了对于千万级别的用户,操作总数达万级别,每日几十亿操作流水的留存分析工具秒级别查询的数据构建方案.同时,除了留存分析,对于用户群分析,事件分析等也可以尝试用此方案来解决. 文章作者: ...

  3. 09-flask-蓝图

    蓝图 作用:分离前后台 代码截图 运行截图 代码 main.py from flask import Flask from view.admin import admin_blu app = Flas ...

  4. Mybatis(二)--SqlMapConfig.xml配置文件

    一.简介 SqlMapConfig.xml是Mybatis的全局配置文件,我们在写mybatis项目时,在SqlMapConfig.xml文件中主要配置了数据库数据源.事务.映射文件等,其实还有很多配 ...

  5. k8s第二回之k8s集群的安装

    1. k8s集群的安装 目录 1. k8s集群的安装 1.架构: 2.环境准备 3.master节点安装etcd 4. master节点安装kubernetes 5.node节点安装kubernete ...

  6. 给因特尔S2600CO服务器主板安装【SAS控制器】驱动

    给因特尔S2600CO服务器主板安装[SAS控制器]驱动 1:首先打开[设备管理器]找到未识别驱动的[SAS控制器]双击进入 2:在[详细信息]选项卡,选择[兼容Id]属性可以看到PCI\VEN_80 ...

  7. BF,BM,KMP,就这?

    为保证代码严谨性,文中所有代码均在 leetcode 刷题网站 AC ,大家可以放心食用. 皇上生辰之际,举国同庆,袁记菜馆作为天下第一饭店,所以被选为这次庆典的菜品供应方,这次庆典对于袁记菜馆是一项 ...

  8. Python文件部分(不包括数据)

    一,基本操作过程:1.a = open(文件名 ,打开方式) 2.a.read(size) | a.readline(size) | a.readlines(hint) 或 a.write(s) | ...

  9. 关于eclipse反编译插件不起作用问题的解决

    1.首先我的eclipse版本是 Version: Photon Release (4.8.0),小伙伴们可以通过 help>>About eclipse IDE 来查看自己的eclips ...

  10. 在wildfly 21中搭建cluster集群

    目录 简介 下载软件和相关组件 配置domain 创建应用程序 部署应用程序 集群配置 总结 简介 wildfly是一个非常强大的工具,我们可以轻松的使用wildfly部署应用程序,更为强大的是,wi ...