Java高阶数据结构-----并查集(详解)

news2024/12/22 16:17:17

目录

🧐一.并查集的基本概念&实例:

🤪二.并查集代码:

😂三:并查集的一些习题:

A.省份数量

B.等式方程的可满足性


🧐一.并查集的基本概念&实例:

并查集概念:将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这类问题的抽象数据类型称为并查集(union-find set)。

 有了上面的一定了解,我们再来看一个实例:

比如:某公司今年校招全国总共招生10人,西安招4人,成都招3人,武汉招3人,10个人来自不同的学校, 起先互不相识,每个学生都是一个独立的小团体,现给这些学生进行编号:{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 给以下 数组用来存储该小集体,数组中的数字代表:该小集体中具有成员的个数。(负号下文解释)

毕业后,学生们要去公司上班,每个地方的学生自发组织成小分队一起上路,于是: 西安学生小分队s1={0,6,7,8},成都学生小分队s2={1,4,9},武汉学生小分队s3={2,3,5}就相互认识了,10个 人形成了三个小团体。假设右三个群主0,1,2担任队长,负责大家的出行。

一趟火车之旅后,每个小分队成员就互相熟悉,称为了一个朋友圈。

在公司工作一段时间后,西安小分队中8号同学与成都小分队1号同学奇迹般的走到了一起,两个小圈子的学生相互介绍,最后成为了一个小圈子:

现在0集合有7个人,2集合有3个人,总共两个朋友圈,负数的个数就是集合的个数

注意事项:

我们一般将数组中的元素初始化为-1

  1. (数组的下标:)             数组的下标对应集合中元素的编号

  2. (数组的值array[i]:) 数组中如果为负数,负号代表根,数字代表该集合中元素个数

  3. (数组的值array[i]:)数组中如果为非负数,代表该元素双亲在数组中的下标

并查集能干的事:

  1. 查找元素属于哪个集合 沿着数组表示树形关系以上一直找到根(即:树中中元素为负数的位置)

  2. 查看两个元素是否属于同一个集合 沿着数组表示的树形关系往上一直找到树的根,如果根相同表明在同一个集合,否则不在

  3. 将两个集合归并成一个集合 将两个集合中的元素合并 将一个集合名称改成另一个集合的名称

🤪二.并查集代码:

import java.util.*;
public class UnionFindSet {
    public int[] elem;

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

    //查询x的根节点,返回根节点的下标
    public int findRoot(int x){
        if(x < 0){
            throw new IndexOutOfBoundsException("下标不合法,是负数");
        }
        //一直等到数组里面的值为负数时,才找到一个根
        while(elem[x] >= 0){
            x = elem[x];
        }
        return x;
    }

    //查询x1和x2是否是同一个集合
    public boolean isSameUnionFindSet(int x1,int x2){
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if(index1 == index2) return true;
        return false;
    }

   //这是合并操作
    public void union(int x1,int x2){
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if(index1 == index2){
            return ;
        }
        elem[index1] = elem[index1] + elem[index2];
        elem[index2] = index1;
    }

    //查询集合的个数
    public int getCount(){
        int count = 0;
        for(int x : elem){
            if(x < 0) count++;
        }
        return count;
    }
}

那我们趁热打铁,来做两道题练习一下: 

😂三:并查集的一些习题:

  • A.省份数量

  • 题目链接:. - 力扣(LeetCode)

思路:我们初始化一个一维数组表示并查集(数组大小为城市的个数),遍历这个二维数组(isConnected[i][j] 表示 i , j 两个城市相连),用并查集将相连接的城市合并到一个集合中,最后统计集合中元素的个数,就是要求的省份个数

class Solution {
    //A.省份数量
    public int findCircleNum(int[][] isConnected) {
        int n = isConnected.length;
        UnionFindSet ufs = new UnionFindSet(n);
      //将连接在一起的城市合并
       for(int i = 0;i < isConnected.length;i++){
        for(int j = 0;j < isConnected[0].length;j++){
            if(isConnected[i][j] == 1){
                ufs.union(i,j);
            }
        }
       }
      //查找连接在一起的城市,即省份的个数,直接返回
        return ufs.getCount();
    }
}
/* 并查集的实现*/
class UnionFindSet {
    public int[] elem;

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

    //查询x的根节点,返回根节点的下标
    public int findRoot(int x){
        if(x < 0){
            throw new IndexOutOfBoundsException("下标不合法,是负数");
        }

        while(elem[x] >= 0){
            x = elem[x];
        }
        return x;
    }

    //查询x1和x2是否是同一个集合
    public boolean isSameUnionFindSet(int x1,int x2){
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if(index1 == index2) return true;
        return false;
    }

   //这是合并操作
    public void union(int x1,int x2){
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if(index1 == index2){
            return ;
        }
        elem[index1] = elem[index1] + elem[index2];
        elem[index2] = index1;
    }

    //查询集合的个数
    public int getCount(){
        int count = 0;
        for(int x : elem){
            if(x < 0) count++;
        }
        return count;
    }

}

运行结果:

 

  • B.等式方程的可满足性

  • 题目链接:. - 力扣(LeetCode)

思路:我们将具有相同属性的元素放入一个集合中,接着再遍历一遍字符串数组,如果字符串中对应的元素是!,说明不是一个集合,再从上述并查集中查找, 如果是一个集合的(矛盾了),返回false;遍历完成后也没有返回false,那么这个等式方程组就满足条件

class Solution {
    //B.等式方程的可满足性
    public boolean equationsPossible(String[] equations) {
        UnionFindSet ufs = new UnionFindSet(26);
      //将具有相同属性的元素放入一个集合中
        for(int i = 0;i < equations.length;i++){
            if(equations[i].charAt(1) == '='){
                ufs.union(equations[i].charAt(0) - 'a',equations[i].charAt(3) - 'a');
            }
        }
      //如果字符串中对应的元素是!,说明不是一个集合,再从上述并查集中查找, (矛盾了)如果是一个集合的,返回false;
        for(int i  = 0;i < equations.length;i++){
           if(equations[i].charAt(1) == '!'){
             //查找根节点的下标位置
            int index1 = ufs.findRoot(equations[i].charAt(0) - 'a');
            int index2 = ufs.findRoot(equations[i].charAt(3) - 'a');
            if(index1 == index2) return false;
           }
        }
        return true;
    }
}
/* 并查集的实现 */
class UnionFindSet {
    public int[] elem;

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

    //查询x的根节点,返回根节点的下标
    public int findRoot(int x){
        if(x < 0){
            throw new IndexOutOfBoundsException("下标不合法,是负数");
        }

        while(elem[x] >= 0){
            x = elem[x];
        }
        return x;
    }

    //查询x1和x2是否是同一个集合
    public boolean isSameUnionFindSet(int x1,int x2){
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if(index1 == index2) return true;
        return false;
    }

   //这是合并操作
    public void union(int x1,int x2){
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if(index1 == index2){
            return ;
        }
        elem[index1] = elem[index1] + elem[index2];
        elem[index2] = index1;
    }

    //查询集合的个数
    public int getCount(){
        int count = 0;
        for(int x : elem){
            if(x < 0) count++;
        }
        return count;
    }
}

运行结果:

 结语: 写博客不仅仅是为了分享学习经历,同时这也有利于我巩固知识点,总结该知识点,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进。同时也希望读者们不吝啬你们的点赞+收藏+关注,你们的鼓励是我创作的最大动力!

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

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

相关文章

5.3 数据模型设计总结

概述&#xff1a; 数据模型设计是指根据需求和目标设计出合适的数据模型的过程。数据模型是对现实世界中数据的抽象和表示&#xff0c;它定义了数据的结构、关系和约束。数据模型设计的目标是保证数据的一致性、完整性和可用性&#xff0c;同时满足系统性能和可扩展性的要求。…

Python基础教程(十二):模块

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

【Java】解决Java报错:IOException during File Operations

文章目录 引言一、IOException的定义与概述1. 什么是IOException&#xff1f;2. IOException的常见触发场景3. 示例代码 二、解决方案1. 检查文件是否存在2. 使用try-with-resources语句3. 捕获和处理IOException4. 使用NIO进行文件操作 三、最佳实践1. 检查文件状态2. 使用try…

为什么你应该本地化你的软件

本地化您的软件是一项战略举措&#xff0c;可以显著提高其成功率和影响力。以下是您应该投资于软件本地化的几个令人信服的原因&#xff1a; 扩大您的市场覆盖范围 通过本地化您的软件&#xff0c;您可以开拓新市场并接触到更广泛的受众。许多用户更喜欢甚至需要他们母语的软…

(十二)人工智能应用--深度学习原理与实战--模型编译及训练参数的选择

神经网络模型的编译实际上是为网络指定几个非常重要的运行参数,包括优化器、损失函数(误差函数】和评价指标,这三者也代表着神经网络的核心运行机制----通过损失函数来计算网络误差、通过优化器来调整网络参数以降低误差、通过评价指标来衡量网络的性能。神经网络训练时除了…

【漏洞复现】Rejetto HTTP文件服务器 未授权RCE漏洞(CVE-2024-23692)

0x01 产品简介 Rejetto HTTP File Server(HFS)是一个基于HTTP协议的文件服务器软件&#xff0c;旨在为用户提供简单、轻量级且易于使用的文件共享解决方案。功能强大、易于使用的文件服务器软件&#xff0c;无论是个人使用还是团队协作&#xff0c;HFS都能满足用户的需求&…

平价蓝牙耳机推荐有哪些?四款平价顶尖机型盘点

对于预算有限但又追求高品质音效的朋友们&#xff0c;平价蓝牙耳机成为了一个非常实用的选择&#xff0c;在市面上琳琅满目的蓝牙耳机中&#xff0c;挑选出性价比极高且性能出众的款式并不容易&#xff0c;作为一个多年的蓝牙耳机发烧友&#xff0c;接下来我就将为大家盘点四款…

《精通ChatGPT:从入门到大师的Prompt指南》第7章:创意写作

第7章&#xff1a;创意写作 7.1 角色设定 角色设定是创意写作中最关键的环节之一。成功的角色设定能够让读者对故事产生共鸣&#xff0c;使故事更加生动有趣。角色不仅仅是情节发展的载体&#xff0c;更是读者情感的投射对象。因此&#xff0c;深入了解如何设定一个生动而有深…

如何使用免费的 Instant Data Scraper快速抓取网页数据

Instant Data Scraper 是一款非常简单易用的网页数据爬虫工具&#xff0c;你不需要任何代码知识&#xff0c;只需要点几下鼠标&#xff0c;就可以把你想要的数据下载到表格里面。以下是详细的使用步骤&#xff1a; 第一步&#xff1a;安装 Instant Data Scraper 打开谷歌浏览…

java:一个springfox swagger2的简单例子

# 示例程序 【pom.xml】 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.3.12.RELEASE</version> </dependency> <dependency><groupId>…

【每日刷题】Day61

【每日刷题】Day61 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 671. 二叉树中第二小的节点 - 力扣&#xff08;LeetCode&#xff09; 2. 2331. 计算布尔二叉树的值…

02-DHCP原理与配置

1、DHCP的工作原理 当局域网中有大量的主机时&#xff0c;如果逐个为每一台主机手动设置IP地址、默认网关、DNS服务器地址等网络参数&#xff0c;这显然是一个费力也未必讨好的办法。 而DHCP服务器的应用&#xff0c;正好可以解决这一问题。 1.1 DHCP是什么 DHCP——动态主机…

单片机多个中断源时的设计思路,(51为例)工作寄存器R0-R7

51单片机中四组工作寄存器&#xff08;R0-R7&#xff09; 参考 可以看出每个工作寄存器区有8个字节即为R0-R7&#xff0c;当不指定使用哪个工作寄存器区的时候默认0区。其他工作区作为普通的RAM使用。特殊功能寄存器中有可以位寻址和不能位寻址的区域 下面文字引用 通过修改…

ABB机器人修改IO信号的具体方法介绍

ABB机器人修改IO信号的具体方法介绍 具体步骤可从参考以下内容: 导出IO配置文件 打开【控制面板】-【配置】-【I/O System】-【文件】-【‘EIO’另存为】,就可以保存IO配置文件【EIO.cfg】用RobotStudio软件打开EIO.cfg文件在软件界面,鼠标右击,选择【I/O信号数据编辑器】选…

嵌入式八股文

C/C基础 C和C有什么区别 C是⾯向对象的语⾔&#xff0c;⽽C是⾯向过程的语⾔&#xff1b; C引⼊ new/delete 运算符&#xff0c;取代了C中的 malloc/free 库函数&#xff1b; C引⼊引⽤的概念&#xff0c;⽽C中没有&#xff1b; C引⼊类的概念&#xff0c;⽽C中没有&#xff…

2024年,计算机相关专业还值得选择吗? 又该如何判断自己是否适合这类专业呢?

文章目录 一、2024年,计算机相关专业还值得选择吗?二、判断自己是否适合这类专业呢&#xff1f;三、哪所大学的计算机专业最好&#xff1f;四、计算机专业是否仍具有长远的发展潜力和就业前景呢? 一、2024年,计算机相关专业还值得选择吗? 在2024年选择大学专业时&#xff0…

人工智能ChatGPT的多种应用:提示词工程

简介 ChatGPT 的主要优点之一是它能够理解和响应自然语言输入。在日常生活中&#xff0c;沟通本来就是很重要的一门课程&#xff0c;沟通的过程中表达的越清晰&#xff0c;给到的信息越多&#xff0c;那么沟通就越顺畅。 和 ChatGPT 沟通也是同样的道理&#xff0c;如果想要 …

WWDC24Swift 6 崭新亮相,迁移至新 GitHub 组织

WWDC24 上的 Swift&#xff1a;Swift 6 崭新亮相&#xff0c;迁移至新 GitHub 组织 在今年的 WWDC24 大会上&#xff0c;苹果隆重推出了备受期待的 Swift 6 版本&#xff0c;并宣布将其迁移至全新的 GitHub 组织&#xff0c;同时庆祝 Swift 诞生十周年。 Swift 6&#xff1a…

DVWA-DC-6

靶机IP:192.168.20.140 kaliIP:192.168.20.128 网络有问题的可以看下搭建Vulnhub靶机网络问题(获取不到IP) 信息收集 nmap扫描靶机端口及版本信息 dirsearch扫目录 发现是个wordpress建站 我们去访问前端界面 存在重定向&#xff0c;修改hosts文件&#xff0c;加入192.168…

性能测试------LoadRunner 详解

性能测试------LoadRunner的使用 一、什么是LoadRunner LoadRunner是一款由Micro Focus&#xff08;以前是Hewlett-Packard或HP公司&#xff09;开发的性能测试工具。它用于测试和分析系统在负载下的行为和性能。具体来说&#xff0c;LoadRunner可以模拟数千名用户同时访问应…