实验名称

最小生成树算法-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. 题解-FJOI2014 树的重心

    FJOI2014 树的重心 \(Q\) 组测试数据.给一棵树大小为 \(n\),求有多少个子树与其重心相同.重心可能有多个. 数据范围:\(1\le Q\le 50\),\(1\le n\le 200 ...

  2. Android Studio中SVN的使用

    1.忽略文件 1)这种方式,每次新建一个项目都要添加,并不是全局的. .idea文件夹 .gradle文件夹 所有的build文件夹 所有的.iml文件 local.properties文件 2)使用 ...

  3. Windows10自带截屏快捷键

    Windows10自带截屏快捷键使用方法大全我们知道,QQ和微信以及第三方浏览器等软件都支持截图功能,但是这个都是基于软件的一个功能,如果我们不打开这些软件的话,就不能实现截图功能,但其实window ...

  4. 【操作系统】页面置换算法(最佳置换算法)(C语言实现)

    [操作系统]页面置换算法(最佳置换算法)(C语言实现) (编码水平较菜,写博客也只是为了个人知识的总结和督促自己学习,如果有错误,希望可以指出) 1.页面置换算法: 在地址映射过程中,若在页面中发现所 ...

  5. zookeeper集群&伪集群模式部署

    1.什么是单机部署 一台服务器上面部署一个单机版本的zookeeper服务,用于提供服务. 2.什么是集群部署? 集群部署就是多台服务器上面各部署单独的一个zookeeper服务,然后组建一个集群 3 ...

  6. Numpy的学习1-创建数据基础

    1 import numpy as np 2 3 array = np.array([[1,2,3],[4,5,6]]) 4 5 print(array) 6 print('number of dim ...

  7. DRF比Django的认证和权限高在哪里

    Django可以用LoginRequiredMixin和PermissionRequiredMixin给类视图添加认证和权限,DRF做了高级封装,提供了更简洁的实现方式.我们通过继续学习官网教程来进行 ...

  8. 学习Python之数据类型

    格式化字符串 字符串格式化是一种非常简洁的特性,它能让我们动态更新字符串中的内容.假设我们有从服务器获取的用户信息,并希望根据该信息显示自定义消息,第一个想法是应用字符串连接之类的东西. first_ ...

  9. C# 数组 ArrayList List<T>区别

    System.Collenctions和System.Collenctions.Generic 中提供了很多列表.集合和数组.例如:List<T>集合,数组Int[],String[] . ...

  10. 根据数据库反向生成PD

    原博文 http://www.360doc.com/content/14/0820/20/12385684_403420399.shtml 步骤 File___Reverse Engineer___D ...