高阶数据结构之并查集

2023-10-27

并查集

        在某些应用问题中,需要将n个不同的元素划分成一些不想交的集合。开始时,每个元素自成一个单元集合,然后按照一定的规律将归于同一组元素的集合进行合并操作。在此过程中需要反复对某个元素进行查询,判断其归属于哪个集合的运算操作,抽象出来的数据结构就叫做“并查集”。

        其实,并查集是一种树形数据结构,只是我们是使用数组来表示树形的结构。总结上面的这一段概念,意思就是说并查集两个基本操作:1.查询一个元素在哪个集合;2.合并两个集合。
        需要注意的是:初始化的数组上的元素都需要初始化成-1。原因是我们指定的规则是需要使用负数来代表根节点,负的这个数来代表自己集合中元素的个数;非负数则用来表示本元素的父节点元素的下标。参考下图。
在这里插入图片描述
        此时假如进行合并操作,将1所在的集合合并到0所在的集合中,会发生这样的变化:
在这里插入图片描述

并查集的常规实现

        以下给出实现并查集的常规代码。

public class UnionFindSet {
    private int[] elem;

    public UnionFindSet(int n){
        this.elem = new int[n];
        Arrays.fill(elem, -1);
    }

    //查找一个元素的根节点
    public int findRoot(int x){
        if(x < 0) return -1;
        while(this.elem[x] >= 0){
            x = this.elem[x];
        }
        return x;
    }

    //查找两个元素是否在同一个集合
    public boolean isSameUnionFindSet(int x, int y){
        int rootX = findRoot(x);
        int rootY = findRoot(y);
        if(rootX != -1 && rootY != -1 && rootX == rootY){
            return true;
        }
        return false;
    }

    //集合合并操作
    public void union(int x, int y){
        int rootX = findRoot(x);
        int rootY = findRoot(y);
        if(rootX == -1 || rootY == -1 || rootX == rootY) return;
        this.elem[rootX] += this.elem[rootY];
        this.elem[rootY] = rootX;
    }

    //获取集合的数量
    public int getCount(){
        int cnt = 0;
        for(int x : this.elem){
            if(x < 0) cnt++;
        }
        return cnt;
    }
}

并查集的简化实现(算法题 - 模板)

        但是在算法题中,肯定不会按照上面这样子写的,因为这样的代码结构过于长。一般我们在做算法题的时候,都是提前把一些常用的模板默写下来,并查集也不例外。而这一版本的并查集会有一个新的规则,可以尽可能兼容同类型的算法题。

朴素的并查集

public class Main{
    public int[] p = new int[N];
    
    // 返回x的祖宗节点
    public int find(int x){
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
    
    public static void main(String[] args){
        
        // 初始化,假定节点编号是1~n
        for(int i = 1; i <= n; i++) p[i] = i;
        
        // 合并a和b所在的两个集合:
        p[find(a)] = find(b);
    }
}

维护size的并查集

public class Main{
    public int[] p = new int[N];
    public int[] size = new int[N];
    
    // 返回x的祖宗节点
    public int find(int x){
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
    
    public static void main(String[] args){
        
        // 初始化,假定节点编号是1~n
        for(int i = 1; i <= n; i++){
            p[i] = i;
            size[i] = 1;
        }
        
        // 合并a和b所在的两个集合:
        size[find(b)] += size[find(a)];
        p[find(a)] = find(b);
    }
}

维护到祖宗节点的并查集

public class Main{
    public int[] p = new int[N];  //存储每个点的祖宗节点
    public int[] d = new int[N];  //存储当前点到祖宗节点的距离
    
    // 返回x的祖宗节点
    public int find(int x){
        if (p[x] != x){
            int u = find(p[x]);
            d[x] += d[p[x]];
            p[x] = u;
        }
        return p[x];
    }
    
    public static void main(String[] args){
        
        // 初始化,假定节点编号是1~n
        for(int i = 1; i <= n; i++){
            p[i] = i;
            d[i] = 0;
        }
        
        // 合并a和b所在的两个集合:
        p[find(a)] = find(b);
        d[find(a)] = distance; // 根据具体问题,初始化find(a)的偏移量
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

高阶数据结构之并查集 的相关文章

随机推荐

  • vue-element el-table 使用sortablejs拖拽排序

    需求描述 vue element admin开发过程中需要对el table行进行排序 即每一行可以上下移动 然后将排序后的数据传给后台更新数据 该表格无分页 问题分析 方法一 可以采用在每条数据中加两个上下移动的按钮 每次移动一行 该方法
  • 自制脚本语言(12) 作用域与符号表

    摘要 介绍了自制语言的编译器对符号表的处理 YF语言中 符号表的基本结构是hash表 每个AST 附带了3个hash表 变量表 类型表 函数表 例如
  • python Django项目点击run或debug时出现Type ‘manage.py help <subcommand>‘ for help on a specific subcommand.

    报错 D python3 7 python exe E code dailyfresh test1 test2 manage py Type manage py help
  • python requests cookies怎么转为_如何将requests.RequestsCookieJar转换为字符串

    新答案 好吧 所以我还是不知道你到底想达到什么目的 如果您想从requests RequestCookieJar对象中提取原始url 这样您就可以检查是否与给定的子域匹配 这是 据我所知 不可能的 不过 你也可以做些类似的事情 usr bi
  • Linux-线程的同步与互斥

    线程的同步与互斥 进程 线程间的互斥相关背景概念 互斥量 互斥量接口 互斥量的初始化 互斥量的销毁 加锁和解锁 改善抢票系统 互斥量原理 可重入与线程安全 重入和线程安全的概念 常见线程不安全情况 常见线程安全的情况 常见不可重入情况 常见
  • 【软件工程】-可行性研究报告

    GB8567 88 可行性研究报告 1引言 1 1编写目的 为了提高机房收费管理的灵活性和效率 减轻机房工作人员的工作负担 节约时间 对机房收费业务做到快速准确管理的目的 从而降低人力 经济的更各方面的消耗 本次编写主要是为了分析廊坊师范学
  • 电机速度曲线规划1:梯形速度曲线设计与实现

    电机驱动是很常见的应用 在很多系统中我们都会碰到需要改变电机的速度以实现相应的控制功能 这就涉及到电机速度曲线规划的问题 在这篇中我们就来简单讨论一下电机的梯形曲线规划的问题 1 基本原理 梯形速度曲线控制算法是工业控制领域应用最为广泛的加
  • 在vc下环境变量的设置

    Error spawning cl exe 编译出错 有人说是没有设置 include环境变量 下面介绍在vc下如何设置环境变量 1 Microsoft Visual Studio下面3个子文件夹 Common VC98 My Projec
  • 1.嵌入式控制器EC学习,编译环境搭建

    工欲善其事 必先利其器 在学习EC相关知识之前 首先需要完成EC代码编译环境的搭建 需要如下内容 Keil C51 用于EC中C代码的编译器环境 EC源代码 我们使用从网上可以下载到的 ITE V12 4 Update 版的代码为例进行学习
  • JavaBean,List,Map转成json格式

    普通JavaBean 以User为例 转成json格式 1 转成JSONArray类型 User user new User user setUsername cxl user setPassword 1234 JSONArray json
  • GORM 基础 -- Gen

    https gorm io gen github 1 GEN Guides GEN 友好和更安全的代码生成 1 1 概述 来自动态原始SQL的惯用和可重用API 100 类型安全的DAO API 不使用 interface Database
  • printf(“%d,%d\n“,i--,i++)

    sample cpp include
  • Windows 下创建定时任务执行Python脚本

    文章目录 一 环境 二 脚本 三 创建定时任务 1 打开 任务计划程序 2 打开 创建任务 窗口 3 创建任务一一常规 4 创建任务一一触发器 5 创建任务一一操作 6 创建任务一一条件 7 创建任务一一设置 8 完成任务创建 四 验证定时
  • 记录自己在结构光三维重建领域的学习过程(一)

    仿真数据集与真是数据集之间差异较大 二者的网络均不可完美预测另一种数据 寻找解决办法 首先确定是不是数据的问题 阅读论文 Light field structured light projection data generation wit
  • 关于存储过程中SQL语句IN条件传参注意说

    背景说明 在数据库操作中我们经常会用到查询语句 在一些情况下 需要使用到IN条件 正常的查询中IN需要注意的是最好in中的参数不能超过1000个 超过1000的时候oracle会抛出异常 这个如何处理先不提 这次要说的是 如果在存储过程中使
  • 某单位分配到一个地址块 136.23.12.64/26。现在需要进一步划分为4个一样大的子网。试问:

    1 每个子网的网络前缀有多长 2 每个子网中有多少个地址 3 每个子网的地址块是什么 4 每一个子网可分配给主机使用的最小地址和最大地址是什么 姐
  • JS中的邮箱验证

    通过js在前端对用户输入进行校验 即可以产生较好的交互体验 也可以减轻后台的压力 邮箱的基本格式要求 1 只能以单词字符开头 即a z A Z 0 9 2 只能有一个 3 后面有一个到多个点 并且点不能在最后 4 特殊字符不能开头和结尾 使
  • 数据存储,详细讲解

    数据存储 详细讲解 数据类型的介绍 整形的内存存储 大小端介绍 浮点数的存储 数据类型的介绍 1 内置类型 char 字符数据类型 1 short 短整型 2 int 整形 4 long 长整型 4 8 long long 更长的整形 8
  • matlab之数组反序输出

    a 1 2 3 4 5 a end 1 1 5 4 3 2 1 转载于 https www cnblogs com yibeimingyue p 11201805 html
  • 高阶数据结构之并查集

    文章目录 并查集 并查集的常规实现 并查集的简化实现 算法题 模板 朴素的并查集 维护size的并查集 维护到祖宗节点的并查集 并查集 在某些应用问题中 需要将n个不同的元素划分成一些不想交的集合 开始时 每个元素自成一个单元集合 然后按照