当前位置: 首页 > news >正文

并查集 rank 的优化(Java 实例代码)

目录

 

并查集 rank 的优化

Java 实例代码

UnionFind3.java 文件代码:


 

并查集 rank 的优化

上一小节介绍了并查集基于 size 的优化,但是某些场景下,也会存在某些问题,如下图所示,操作 union(4,2)。

 

7561a182ed69e7dafb5bef57311d44d5.png

根据上一小节,size 的优化,元素少的集合根节点指向元素多的根节点。操作完后,层数变为4,比之前增多了一层,如下图所示:

 

3fb31fb1d2b9eac6cddd03a4181a5e66.png

由此可知,依靠集合的 size 判断指向并不是完全正确的,更准确的是,根据两个集合层数,具体判断根节点的指向,层数少的集合根节点指向层数多的集合根节点,如下图所示,这就是基于 rank 的优化。

 

56512f102f1baf3bf7b91a8c2c34d19b.png

我们在并查集的属性中,添加 rank 数组,rank[i] 表示以 i 为根的集合所表示的树的层数。

...
private int[] rank;   // rank[i]表示以i为根的集合所表示的树的层数
private int[] parent; // parent[i]表示第i个元素所指向的父节点
private int count;    // 数据个数
...

构造函数相应作出修改:

...
// 构造函数
public UnionFind4(int count){
    rank = new int[count];
    parent = new int[count];
    this.count = count;
    // 初始化, 每一个parent[i]指向自己, 表示每一个元素自己自成一个集合
    for( int i = 0 ; i < count ; i ++ ){
        parent[i] = i;
        rank[i] = 1;
    }
}
...

合并两元素的时候,需要比较根节点集合的层数,整个过程是 O(h)复杂度,h为树的高度。

...
public void unionElements(int p, int q){
    int pRoot = find(p);
    int qRoot = find(q);
    if( pRoot == qRoot )
        return;

    if( rank[pRoot] < rank[qRoot] ){
        parent[pRoot] = qRoot;
    }
    else if( rank[qRoot] < rank[pRoot]){
        parent[qRoot] = pRoot;
    }
    else{ // rank[pRoot] == rank[qRoot]
        parent[pRoot] = qRoot;
        rank[qRoot] += 1;   // 此时, 我维护rank的值
    }
}
...

Java 实例代码

源码包下载:Download

UnionFind3.java 文件代码:

package runoob.union;
/**
 * 基于rank的优化
 */
public class UnionFind4 {
    private int[] rank;   // rank[i]表示以i为根的集合所表示的树的层数
    private int[] parent; // parent[i]表示第i个元素所指向的父节点
    private int count;    // 数据个数
    // 构造函数
    public UnionFind4(int count){
        rank = new int[count];
        parent = new int[count];
        this.count = count;
        // 初始化, 每一个parent[i]指向自己, 表示每一个元素自己自成一个集合
        for( int i = 0 ; i < count ; i ++ ){
            parent[i] = i;
            rank[i] = 1;
        }
    }
    // 查找过程, 查找元素p所对应的集合编号
    // O(h)复杂度, h为树的高度
    private int find(int p){
        assert( p >= 0 && p < count );
        // 不断去查询自己的父亲节点, 直到到达根节点
        // 根节点的特点: parent[p] == p
        while( p != parent[p] )
            p = parent[p];
        return p;
    }
    // 查看元素p和元素q是否所属一个集合
    // O(h)复杂度, h为树的高度
    public boolean isConnected( int p , int q ){
        return find(p) == find(q);
    }
    // 合并元素p和元素q所属的集合
    // O(h)复杂度, h为树的高度
    public void unionElements(int p, int q){
        int pRoot = find(p);
        int qRoot = find(q);
        if( pRoot == qRoot )
            return;
        if( rank[pRoot] < rank[qRoot] ){
            parent[pRoot] = qRoot;
        }
        else if( rank[qRoot] < rank[pRoot]){
            parent[qRoot] = pRoot;
        }
        else{ // rank[pRoot] == rank[qRoot]
            parent[pRoot] = qRoot;
            rank[qRoot] += 1;   // 维护rank的值
        }
    }
}

 

http://www.lryc.cn/news/134115.html

相关文章:

  • TDA4超级玩家浮出水面,行泊一体功能、成本刷到极致
  • 3分钟了解Android中稳定性测试
  • LVS-DR+keepalived实现高可用负载群集
  • 阿里云国际版注册教程
  • 基于百度文心大模型创作的实践与谈论
  • Java基础知识题(五)
  • 攻防世界-fileinclude
  • 流媒体服务器SRS的搭建及QT下RTMP推流客户端的编写
  • Effective C++条款11——在operator=中处理“自我赋值”(构造/析构/赋值运算)
  • 可视化绘图技巧100篇基础篇(八)-气泡图(一)
  • Elasticsearch查询之Disjunction Max Query
  • Lock wait timeout exceeded; try restarting transaction的错误
  • ShardingSphere01-docker环境安装
  • Java代码审计13之URLDNS链
  • 区间预测 | MATLAB实现QRBiGRU双向门控循环单元分位数回归时间序列区间预测
  • Python面向对象植物大战僵尸
  • 大屏模板,增加自适应(包含websocket)
  • 电商系统架构设计系列(九):如何规划和设计分库分表?
  • 从Web 2.0到Web 3.0,互联网有哪些变革?
  • QT中资源文件resourcefile的使用,使用API完成页面布局
  • 2337. 移动片段得到字符串
  • Java并发编程第5讲——volatile关键字(万字详解)
  • 6.小程序api分类
  • 什么是PPS和TOD时序?授时防护设备是什么?
  • 推荐一款好用的开源视频播放器(免费无广告)
  • STM32 CubeMX (第三步Freertos中断管理和软件定时)
  • Java虚拟机(JVM):堆溢出
  • C语言,Linux,静态库编写方法,makefile与shell脚本的关系。
  • Php“牵手”淘宝商品详情页数据采集方法,淘宝API接口申请指南
  • 如何使用CSS实现一个全屏滚动效果(Fullpage Scroll)?