我的编程空间,编程开发者的网络收藏夹
学习永远不晚

java中并查集的示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

java中并查集的示例分析

这篇文章主要介绍了java中并查集的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

一、概述

并查集:一种树型数据结构,用于解决一些不相交集合的合并及查询问题。例如:有n个村庄,查询2个村庄之间是否有连接的路,连接2个村庄

两大核心:

查找 (Find) : 查找元素所在的集合

合并 (Union) : 将两个元素所在集合合并为一个集合

二、实现

并查集有两种常见的实现思路

快查(Quick Find)

  • 查找(Find)的时间复杂度:O(1)

  • 合并(Union)的时间复杂度:O(n)

快并(Quick Union)

  • 查找(Find)的时间复杂度:O(logn)可以优化至O(a(n))a(n)< 5

  • 合并(Union)的时间复杂度:O(logn)可以优化至O(a(n))a(n)< 5

使用数组实现树型结构,数组下标为元素,数组存储的值为父节点的值

java中并查集的示例分析

创建抽象类Union Find

public abstract class UnionFind {  int[] parents;public UnionFind(int capacity){if(capacity < 0) {throw new IllegalArgumentException("capacity must be >=0");}        //初始时每一个元素父节点(根结点)是自己parents = new int[capacity];for(int i = 0; i < parents.length;i++) {parents[i] = i;}}   public boolean isSame(int v1,int v2) {return find(v1) == find(v2);}     public  abstract int find(int v); public abstract void union(int v1, int v2);// 范围检查public   void rangeCheck(int v)  {if(v<0 || v > parents.length)throw new IllegalArgumentException("v is out of capacity");}}

2.1 Quick Find实现

以Quick Find实现的并查集,树的高度最高为2,每个节点的父节点就是根节点

java中并查集的示例分析

public class UnionFind_QF extends UnionFind {public UnionFind_QF(int capacity) {super(capacity);}   // 查@Overridepublic  int  find(int v) {rangeCheck(v);return parents[v];}  // 并 将v1所在集合并到v2所在集合上@Overridepublic void union(int v1, int v2) {    // 查找v1 v2 的父(根)节点int p1= find(v1);int p2 = find(v2);if(p1 == p2) return;      //将所有以v1的根节点为根节点的元素全部并到v2所在集合上 即父节点改为v2的父节点for(int i = 0; i< parents.length; i++) {if(parents[i] == p1) {parents[i] = p2;}}  }}

2.2 Quick Union实现

java中并查集的示例分析

public class UnionFind_QU extends UnionFind { public UnionFind_QU(int capacity) {super(capacity);} //查某一个元素的根节点@Overridepublic int find(int v) {   //检查下标是否越界rangeCheck(v);     // 一直循环查找节点的根节点while (v != parents[v]) {v = parents[v];}return v;} //V1 并到 v2 中@Overridepublic void union(int v1, int v2) {int p1 = find(v1);int p2 = find(v2);if(p1 == p2) return;      //将v1 根节点 的 父节点 修改为 v2的根结点 完成合并parents[p1] = p2;}}

三、优化

并查集常用快并来实现,但是快并有时会出现树不平衡的情况

java中并查集的示例分析

有两种优化思路:rank优化,size优化 

3.1基于size的优化

核心思想:元素少的树 嫁接到 元素多的树

public class UniondFind_QU_S extends UnionFind{    // 创建sizes 数组记录 以元素(下标)为根结点的元素(节点)个数private int[] sizes; public UniondFind_QU_S(int capacity) {super(capacity); sizes = new int[capacity];    //初始都为 1for(int i = 0;i < sizes.length;i++) {sizes[i] = 1;}} @Overridepublic int find(int v) { rangeCheck(v); while (v != parents[v]) {v = parents[v];}return v;} @Overridepublic void union(int v1, int v2) {int p1 = find(v1);int p2 = find(v2);if(p1 == p2) return; //如果以p1为根结点的元素个数 小于 以p2为根结点的元素个数 p1并到p2上,并且更新p2为根结点的元素个数if(sizes[p1] < sizes[p2]) {    parents[p1] = p2;    sizes[p2] += sizes[p1]; // 反之 则p2 并到 p1 上,更新p1为根结点的元素个数}else {parents[p2] = p1;sizes[p1] += sizes[p2];}}}

基于size优化还有可能会导致树不平衡

3.2基于rank优化

核心思想:矮的树 嫁接到 高的树

public class UnionFind_QU_R extends UnionFind_QU {   // 创建rank数组  ranks[i] 代表以i为根节点的树的高度 private int[] ranks; public UnionFind_QU_R(int capacity) {super(capacity); ranks = new int[capacity]; for(int i = 0;i < ranks.length;i++) {ranks[i] = 1;} }    public void union(int v1, int v2) { int p1 = find(v1);int p2 = find(v2);if(p1 == p2) return;        // p1 并到 p2 上 p2为根 树的高度不变if(ranks[p1] < ranks[p2]) {parents[p1] = p2;  // p2 并到 p1 上 p1为根 树的高度不变} else if(ranks[p1] > ranks[p2]) {parents[p2] = p1; }else {    // 高度相同 p1 并到 p2上,p2为根 树的高度+1parents[p1] = p2;ranks[p2] += 1;}}}

基于rank优化,随着Union次数的增多,树的高度依然会越来越高  导致find操作变慢

有三种思路可以继续优化 :路径压缩、路径分裂、路径减半

3.2.1路径压缩(Path Compression )

在find时使路径上的所有节点都指向根节点,从而降低树的高度

java中并查集的示例分析

public class UnionFind_QU_R_PC extends UnionFind_QU_R { public UnionFind_QU_R_PC(int capacity) {super(capacity);} @Overridepublic int find(int v) {rangeCheck(v); if(parents[v] != v) {         //递归 使得从当前v 到根节点 之间的 所有节点的 父节点都改为根节点parents[v] = find(parents[v]);}return parents[v];}}

虽然能降低树的高度,但是实现成本稍高 

3.2.2路径分裂(Path Spliting)

使路径上的每个节点都指向其祖父节点

java中并查集的示例分析

public class UnionFind_QU_R_PS extends UnionFind_QU_R { public UnionFind_QU_R_PS(int capacity) {super(capacity);} @Overridepublic int find(int v) {rangeCheck(v);while(v != parents[v]) { int p = parents[v];parents[v] = parents[parents[v]];v = p;}return v;}}
3.2.3路径减半(Path Halving)

使路径上每隔一个节点就指向其祖父节点

java中并查集的示例分析

public class UnionFind_QU_R_PH extends UnionFind_QU_R { public UnionFind_QU_R_PH(int capacity) {super(capacity);}    public int find(int v) {    rangeCheck(v); while(v != parents[v]) {parents[v] = parents[parents[v]];v = parents[v];}return v;}  }

使用Quick Union + 基于rank的优化 + 路径分裂 或 路径减半

可以保证每个操作的均摊时间复杂度为O(a(n)) , a(n) < 5

感谢你能够认真阅读完这篇文章,希望小编分享的“java中并查集的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网行业资讯频道,更多相关知识等着你来学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

java中并查集的示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

java中并查集的示例分析

这篇文章主要介绍了java中并查集的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、概述并查集:一种树型数据结构,用于解决一些不相交集合的合并及查询问题。例如:有n
2023-06-29

Java中集合的示例分析

小编给大家分享一下Java中集合的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!java集合java集合类存放于java.util包中,是一个用来存放对象
2023-06-20

java集合中list的示例分析

这篇文章主要为大家展示了“java集合中list的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“java集合中list的示例分析”这篇文章吧。1、List接口该接口定义的元素是有序的且可
2023-05-30

java集合的示例分析

这篇文章主要介绍了java集合的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、简介1、java集合框架图从上面的集合框架图可以看到,Java 集合框架主要包括两种
2023-06-20

JAVA中集合体系的示例分析

这篇文章给大家分享的是有关JAVA中集合体系的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、集合概况Java是一种面向对象语言,如果我们要针对多个对象进行操作,那么首先必要将多个对象进行保存起来之后,
2023-05-30

Java中并发容器的示例分析

这篇文章给大家分享的是有关Java中并发容器的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、并发容器1.1 JDK 提供的并发容器总结JDK 提供的这些容器大部分在java.util.concurre
2023-06-15

Java Map集合的示例分析

这篇文章将为大家详细讲解有关Java Map集合的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、前言map集合是我们常使用的集合,了解和使用map集合是必要的二、Map介绍基本形式: publ
2023-06-25

java8集合求差集、并集、交集的示例分析

这篇文章将为大家详细讲解有关java8集合求差集、并集、交集的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。前言java8里最大亮点是lambda,让我们用习惯C# linq的语法,也能眼前一亮。
2023-05-30

Java中集合关系图的示例分析

这篇文章主要介绍Java中集合关系图的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!下面是一张下载的Java中的集合类型的继承关系图,便于正确的理解和使用相应的集合类型。 几个面试常见问题:1.Q:Arra
2023-05-30

java高并发中并发级别的示例分析

这篇文章给大家分享的是有关java高并发中并发级别的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。阻塞一个线程是阻塞的,那么在其他线程释放资源之前,当前线程无法继续执行。当我们使用synchronized
2023-06-25

Java并发中AQS原理的示例分析

这篇文章给大家分享的是有关Java并发中AQS原理的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1、线程阻塞原语Java 的线程阻塞和唤醒是通过 Unsafe 类的 park 和 unpark 方法做到
2023-06-02

java并发中wait notify notifyAll的示例分析

这篇文章主要介绍java并发中wait notify notifyAll的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、前言java 面试是否有被问到过,sleep 和 wait 方法的区别,关于这个问题
2023-06-15

Java中多线程与并发的示例分析

这篇文章主要介绍Java中多线程与并发的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、进程与线程进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。线程:是进程的一个执行路径,一个
2023-06-15

python中集合的示例分析

这篇文章主要介绍python中集合的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、集合的基本信息集合:集合是无序的,集合中的元素是唯一的,集合一般用于元组或者列表中的元素去重。格式:set1 = set(
2023-06-15

JAVA并发中VOLATILE关键字的示例分析

小编给大家分享一下JAVA并发中VOLATILE关键字的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!并发编程中的三个概念:1.原子性在Java中,对基本
2023-06-15

Java并发中守护线程的示例分析

今天就跟大家聊聊有关Java并发中守护线程的示例分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在Java中有两类线程:用户线程 (User Thread)、守护线程 (Daemo
2023-06-17

java中斐波那契查找的示例分析

这篇文章给大家分享的是有关java中斐波那契查找的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。本教程操作环境:windows7系统、java10版,DELL G3电脑。1.概念是二分查找的一种提升算法,
2023-06-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录