【数据结构-图】并查集

news2024/11/28 7:44:06

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
img

  • 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老
  • 导航
    • 檀越剑指大厂系列:全面总结 java 核心技术点,如集合,jvm,并发编程 redis,kafka,Spring,微服务,Netty 等
    • 常用开发工具系列:罗列常用的开发工具,如 IDEA,Mac,Alfred,electerm,Git,typora,apifox 等
    • 数据库系列:详细总结了常用数据库 mysql 技术点,以及工作中遇到的 mysql 问题等
    • 懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
    • 数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

博客目录

    • 一.介绍说明
      • 1.什么是并查集
      • 2.并查集模版
    • 二.具体实现
      • 1.基础实现
      • 2.路径压缩
      • 3.按秩合并

一.介绍说明

1.什么是并查集

并查集(Disjoint-Set,也称为不相交集合或 Union-Find 数据结构)是一种用于处理集合合并与查询等操作的数据结构。它通常被用来维护一组元素,这些元素被划分成若干个不相交的集合,每个集合具有一个代表元素,通常是集合中的一个元素。

并查集支持以下两种主要操作:

  1. 合并(Union): 将两个不相交的集合合并为一个集合。这意味着两个集合的代表元素会变成同一个,并且它们的元素都属于同一个集合。

  2. 查找(Find): 查找一个元素所属的集合,通常返回该集合的代表元素。这个操作通常用于判断两个元素是否属于同一个集合。

并查集的一个关键特性是,它以非常高效的方式支持这两种操作。通常,这是通过树结构来实现的,其中每个集合都是一棵树,树的根节点是代表元素。这些树可以很高效地合并(通过将一棵树的根节点连接到另一棵树的根节点)以及查找(通过遵循树的父指针链路找到根节点)。

并查集广泛用于解决各种问题,包括连通性问题、划分问题、最小生成树算法中的 Kruskal 算法等。它是一个重要的数据结构,用于高效地管理和操作不相交集合。常见的并查集实现包括基于树结构的普通并查集和基于树结构的优化版本,如按秩合并和路径压缩。这些优化可以进一步提高并查集的性能。

2.并查集模版

以下是一个简单的并查集的 Java 模板,包括基本的合并和查找操作,以及按秩合并和路径压缩的优化:

class UnionFind {
    private int[] parent; // 用于存储每个元素的父节点
    private int[] rank; // 用于记录树的深度(秩)

    public UnionFind(int size) {
        parent = new int[size];
        rank = new int[size];

        // 初始化,每个元素的父节点是它自己,秩为0
        for (int i = 0; i < size; i++) {
            parent[i] = i;
            rank[i] = 0;
        }
    }

    // 查找操作(Find)
    public int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]); // 路径压缩
        }
        return parent[x];
    }

    // 合并操作(Union)
    public void union(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);

        if (rootX != rootY) {
            // 按秩合并,将深度较小的树合并到深度较大的树下面
            if (rank[rootX] < rank[rootY]) {
                parent[rootX] = rootY;
            } else if (rank[rootX] > rank[rootY]) {
                parent[rootY] = rootX;
            } else {
                parent[rootY] = rootX;
                rank[rootX]++;
            }
        }
    }
}

使用上述模板,你可以创建一个并查集对象,并使用它执行合并和查找操作。例如:

UnionFind uf = new UnionFind(5); // 创建一个包含5个元素的并查集

uf.union(0, 1); // 合并元素0和元素1所在的集合
uf.union(2, 3); // 合并元素2和元素3所在的集合

boolean isConnected = uf.find(0) == uf.find(1); // 检查元素0和元素1是否属于同一个集合,应返回true

这是一个基本的并查集模板,你可以根据需要进行扩展和修改,以适应具体问题的要求。

二.具体实现

1.基础实现

public class DisjointSet {
    int[] s;
    // 索引对应顶点
    // 元素是用来表示与之有关系的顶点
    /*
        索引  0  1  2  3  4  5  6
        元素 [0, 1, 2, 3, 4, 5, 6] 表示一开始顶点直接没有联系(只与自己有联系)

    */

    public DisjointSet(int size) {
        s = new int[size];
        for (int i = 0; i < size; i++) {
            s[i] = i;
        }
    }

    // find 是找到老大
    public int find(int x) {
        if (x == s[x]) {
            return x;
        }
        return find(s[x]);
    }

    // union 是让两个集合“相交”,即选出新老大,x、y 是原老大索引
    public void union(int x, int y) {
        s[y] = x;
    }

    @Override
    public String toString() {
        return Arrays.toString(s);
    }

}

2.路径压缩

public int find(int x) { // x = 2
    if (x == s[x]) {
        return x;
    }
    return s[x] = find(s[x]); // 0    s[2]=0
}

3.按秩合并

Union By Size

public class DisjointSetUnionBySize {
    int[] s;// 用于存储每个元素的父节点
    int[] size;//用于记录树的深度(秩)
    public DisjointSetUnionBySize(int size) {
        s = new int[size];
        this.size = new int[size];
        for (int i = 0; i < size; i++) {
            s[i] = i;
            this.size[i] = 1;
        }
    }

    // find 是找到老大 - 优化:路径压缩
    public int find(int x) { // x = 2
        if (x == s[x]) {
            return x;
        }
        return s[x] = find(s[x]); // 0    s[2]=0
    }

    // union 是让两个集合“相交”,即选出新老大,x、y 是原老大索引
    public void union(int x, int y) {
//        s[y] = x;
        if (size[x] < size[y]) {
            int t = x;
            x = y;
            y = t;
        }
        s[y] = x;
        size[x] = size[x] + size[y];
    }

    @Override
    public String toString() {
        return "内容:"+Arrays.toString(s) + "\n大小:" + Arrays.toString(size);
    }

    public static void main(String[] args) {
        DisjointSetUnionBySize set = new DisjointSetUnionBySize(5);

        set.union(1, 2);
        set.union(3, 4);
        set.union(1, 3);
        System.out.println(set);
    }
}

觉得有用的话点个赞 👍🏻 呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1042044.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

接口测试主要测试哪方面?需要哪些技能?要怎么学习?

1、什么是接口测试&#xff1f; 定义&#xff1a;测试系统组件间接口的一种测试。主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点&#xff0c;重点是检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等。 目的&#x…

选择合适的外贸公司邮箱注册服务提供商

随着全球化的发展&#xff0c;越来越多的企业开始涉足外贸领域。而在进行外贸业务时&#xff0c;邮箱是必不可少的工具之一。对于外贸公司来说&#xff0c;应该选择哪家邮箱服务提供商呢&#xff1f;口碑好安全性高的公司邮箱有Zoho Mail、阿里邮箱、腾讯邮箱、网易邮箱等。 首…

Spring cloud Sentinel介绍和安装

Sentinel介绍和安装 &#x1f308;初识Sentinel&#x1f308;安装Sentinel&#x1f320;docker 安装&#x1f320;下载sentinel镜像&#x1f320;启动sentinel镜像 &#x1f320;windows 安装&#x1f320;下载&#x1f320;运行 &#x1f320;sentinel访问 &#x1f308;微服务…

上海股票开户佣金最低是多少?怎么开万一账户!

上海股票开户佣金最低是多少&#xff1f;怎么开万一账户&#xff01; 股票开户是指向证券公司或经纪人申请开通股票交易账户的过程。开户时需要提供个人身份信息和相关资料&#xff0c;完成相关的申请、签署协议以及缴纳开户费用。开户后&#xff0c;投资者就可以在证券市场上…

8年测试老鸟总结,Python自动化测试实现思路(细致)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试…

NVM:切换node版本后无法使用npm全局包

1.新建文件夹npm_global和npm_cache 2.npm设置 npm config set prefix "C:\Users\18068\node\node_global" npm config set cache "C:\Users\18068\node\node_cache" 3.设置环境变量 新建NVM_PATH环境变量 选择缓存目录 编辑PATH环境变量 新建%NVM_PA…

睿趣科技:新手抖音开店卖什么产品好

抖音已经成为了一款年轻人热爱的社交媒体应用&#xff0c;同时也成为了一种全新的电商平台。对于新手来说&#xff0c;抖音开店卖什么产品是一个备受关注的问题。在这篇文章中&#xff0c;我们将探讨一些适合新手的产品选择&#xff0c;帮助他们在抖音上开店获得成功。 流行时尚…

docker自定义网络下 :不同容器的nginx通过容器名称相互访问PHP项目

场景&#xff1a;每个服务都有自己运行的一套环境&#xff0c;分别都有自己的nginx &#xff1b;我们像用A容器的Nginx 的项目访问到B容器下的nginx项目内容&#xff0c;并且在自定义的网络下面 首先我们可以自定义一个网络&#xff1a;docker默认桥接&#xff1a; docker ne…

03. Springboot集成Mybatis-flex(一)

目录 1、前言 2、MyBatis-Flex 是什么&#xff1f; 3、框架功能对比 4、性能对比 5、快速使用 5.1、Maven添加依赖 5.2、数据源配置 5.3、创建实体类和表 5.4、创建Dao 5.5、创建Service 5.6、创建Controller接口测试 5.7、测试结果 6、小结 1、前言 现在主流的M…

git报错:git Permission denied, please try again.

1 问题描述: git clone/pull代码时提示输入密码,密码输入正确但是报错:git Permission denied, please try again. 2 解决方案: step1 检查SSH Key是否存在#cd ~/.ssh #lsstep2 获取SSH Key如果存在id_rsa.pub 或 id_dsa.pub 文件,跳过此步。 如果不存在,则生成: 先查…

浙江移动与中兴通讯合作项目被评为“光华杯”东部赛区一等奖!

近日&#xff0c;浙江移动携手中兴通讯共同打造的创新合作项目“构建面向东数西算的传输全光底座赋能美丽浙江”在2023年第二届“光华杯”东部赛区决赛中被评为一等奖&#xff0c;该项目以运力为核心&#xff0c;可实践应用于“东数西算”建设工程当中&#xff0c;提供高速无阻…

8. 基于消影点进行相机内参(主点)的标定

目录 1. ocam模型2. 消影点3. 基于消影点进行相机主点标定3.1 基于ocam模型的主点标定 感谢大家的阅读。 1. ocam模型 可以参考我的另一篇博客ocam模型。 这里简单提一下ocam模型&#xff1a; 这个模型将中心折反射相机和鱼眼相机统一在一个通用模型下&#xff0c;也称为泰勒模…

深眸科技迭代深度学习算法,以AI机器视觉技术扩围工业应用场景

智能制造是制造业数智化转型升级的发展方向&#xff0c;在当前以高端装备制造为核心的工业4.0时代背景下&#xff0c;越来越多的制造企业意识到机器视觉对于提高效率、降低成本&#xff0c;从而提升企业效益的意义。 目前&#xff0c;机器视觉已成为制造业迈向智能制造过程中极…

XC6206 低压线性稳压器 300mA低功耗LDO

XC6206系列是一款采用CMOS和激光修整技术制造的高精度、低能耗、3端子、正电压调压器。该系列提供了一个大的电流和一个明显的小的辍学电压。 XC6206由限流器电路、驱动器晶体管、精确参考电压和纠错电路组成。该系列兼容低ESR陶瓷电容。电流限制器的折叠电路作为短路保护以及输…

利用EXCEL进行XXE攻击

利用EXCEL进行XXE攻击 原因 原因 Microsoft Office从2007版本引入了新的开放的XML文件格式&#xff0c;新的XML文件格式基于压缩的ZIP文件格式规范&#xff0c;由许多部分组成。 我们可以将其解压缩到特定的文件夹中来查看其包含的文件夹和文件&#xff0c;可以发现其中多数是…

canvas绘制网格背景

/*** Event 方法* description: canvas 绘制网格背景* */drawGrid(element, lineColor, lineStepX, lineStepY, bgColor, bgStepX, bgStepY) {const canvas document.querySelector(element)const context canvas.getContext(2d)context.save();context.lineWidth 0.5;conte…

Mac cocoapods 3分钟安装教程( 国内镜像源方法)

参考链接&#xff1a;2023最新总结&#xff0c;Mac下使用Homebrew完全指南&#xff01; - 知乎 1.打开终端&#xff0c; 执行&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 2.运行&#xff0c;可以选择清…

Hazelcast系列(二):hazelcast集成

系列文章 Hazelcast系列(一)&#xff1a;初识hazelcast Hazelcast系列(二)&#xff1a;hazelcast集成 目录 前言 集成 环境 配置 配置一 配置二 配置三 测试 其他 总结 前言 前面通过 Hazelcast系列(一)&#xff1a;初识hazelcast 让我们对Hazelcast有了一个大…

Leetcode:【485. 最大连续 1 的个数】

题目 给定一个二进制数组 nums &#xff0c; 计算其中最大连续 1 的个数。 难度&#xff1a;简单 题目链接&#xff1a;485. 最大连续 1 的个数 示例1&#xff1a; 输入&#xff1a;nums [1,1,0,1,1,1] 输出&#xff1a;3 解释&#xff1a;开头的两位和最后的三位都是连续 1 …

JavaScript 基础第四天笔记

JavaScript 基础 - 第4天笔记 理解封装的意义&#xff0c;能够通过函数的声明实现逻辑的封装&#xff0c;知道对象数据类型的特征&#xff0c;结合数学对象实现简单计算功能。 理解函数的封装的特征掌握函数声明的语法理解什么是函数的返回值知道并能使用常见的内置函数 函数 …