文章详情

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

请输入下面的图形验证码

提交验证

短信预约提醒成功

java中并查集的示例分析

2023-06-29 16:22

关注

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

一、概述

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

两大核心:

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

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

二、实现

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

快查(Quick Find)

快并(Quick Union)

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

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

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯