并查集引入

news2024/11/26 2:25:45

目的

主要是处理一些不相交集合的合并问题,比如:求连通子图,求最小生成树的克鲁斯卡尔算法以及最近公共祖先(LCA)等

简单应用就是连通图,将元素进行合并,如果要优化路径的话可以利用数据压缩

三大步骤

1.初始化
2.查询
3.合并

1.初始化

首先我们将所有节点的父节点设置为自己
fa[i]=i :比如fa[i]=j——>代表i的父元素是j
在这里插入图片描述

2.查询

寻找i元素的祖先(寻找代表元素,也就是公共节点)
**结束条件:**节点祖先节点为本身
在这里插入图片描述

3.合并

找到两个节点的祖先,然后将i的祖先指向j的祖先完成合并

在这里插入图片描述

优化

比如 union(4,6) ,4的父节点为3,3的父节点为2,这样递归下去,需要查询的次数太多

优化:路径压缩
比如 union(4,5),4的父节点为3,所以fa[4]=3,fa[3]=2,fa[2]=1,fa[1]=1为结束末尾条件
所以我们在find()方法中加一条语句进行路径压缩

int find(int i){
 if(i==fa[i]){
  return i;
}else{
  fa[i]=find(fa[i]); //进行路径压缩
  return fa[i]; //返回父节点
}

会发现链条发生转变,本质就是利用递归,调用父节点的父节点直至满足结束条件
在这里插入图片描述

实例

一开始有n伙山贼, 他们各自为营 但是他们都是有野心的
第3伙强盗 打下了第5伙强盗 第5伙强盗的老大就是第3伙强盗

然后第7伙强盗一看想要让第5伙强盗成为伙伴 打完第5伙还得打第3伙强盗
还不如直接打第3伙 于是第7伙强盗就打赢了第3伙强盗 然后第3伙和第5伙都归第7伙了

接下来就是各自纷争 然后最后看还剩下了几伙强盗 并且每一伙强盗都是谁

public class UnionFind {
    private int[] id;     存储这几伙强盗的逻辑关系 数组下标i代表第i伙强盗 值代表 他老大是谁
    private int count;    表示一共有几个强盗团伙
    
    public UnionFind(int N)   做初始化操作 N 代表一开始有几伙强盗
    
    public int getCount()     获取强盗团伙的数量
    
    public boolean connected(int p, int q)   判断 p 和 q 这两伙强盗 是不是一家的
    
    public int find(int p)   找到第p伙强盗的老大
    
    public void union(int p, int q)  联合两伙强盗
}

1.构造方法

首先,大家肯定都是各自为营,所以说强盗团伙的数量 就等于强盗数量本身 所以 count = N
然后new出这N伙强盗的逻辑关系,长度就是一开始的强盗数量
最后一句话 大家各自为营 id[i] = i; 自己的老大就是自己

 public UnionFind(int N) {
        count = N;
        id = new int[N];
        for(int i = 0; i < N; i++) id[i] = i;
    }

2.返回强盗数量

public int getCount() {
        return count;
    }

3.查找强盗的上级

 public int find(int p) {
        return id[p];
    }

4.判断P和Q是否存在同一个上级

public boolean connected(int p, int q) {
        return find(p) == find(q);
    }

5.联合

将q作为p的老大,首先得到pq的老大,然后判断是否为同一个人,如果老大都一样说明都是一路人啥也不要做

否则p要被q干掉,从而q当p的老大——>遍历数组,只要发现第i路人马的老大就是p的老大,就让他们的老大变为q,记得最后团队-1

public void union(int p, int q){
        int pRoot = find(p);
        int qRoot = find(q);
        
        if(pRoot == qRoot) return;
        
        for(int i = 0; i < id.length; i++) 
            if(id[i] == pRoot)  id[i] = qRoot;
        count--;
    }

优化

其他方法不用变 只需要 修改 find() 和 union的两个方法就可以 首先看一下 find()

public int find(int p) {
        while(p != id[p]) p = id[p];
        return p;
    }

迭代遍历的是什么? 只要id[p]表示第p伙强盗的 老大
只要老大不是自己就寻找真正的老大
要注意这里你可以有点误区 因为其实我们的union() 方法也改了 这次做的并不是统一老大
上一个版本 我们3干掉了5 3就是5的老大 然后7干掉了3 3的老大和5的老大都变成了7
这次我们是3干掉了5 3就是5的老大 7干掉了3 3的老大是7 5的老大还是3
所以7是5的老大的老大

看一下 union()方法

public void union(int p, int q){
        int pRoot = find(p);
        int qRoot = find(q);

        if(pRoot == qRoot) return;

        id[pRoot] = qRoot;
        count--;
    }

这个就像一棵树,不像之前的把5的老大从6改为7,那么4的老大原本也是6就会收到影响也为7,因为6被7干掉了,强盗团队-1
在这里插入图片描述
这里3干掉了5 就给3和5 连一条线 并且 ip[5] = 3;
在这里插入图片描述
然后7干掉了3 就让3连向7 但是5还是连着3的 ip[3] = 7;
然后find查找5的时候 发现5的老大是3 然后p = 3 然后ip[3] != 3;说明 3还有老大 继续寻找3的老大
然后p=7; 发现7的老大就是7 所以出循环 并且返回7
——>find()方法修改的意义,就是为了判断自己是否还有老大
这样的时间复杂度只取决于 这棵连接起来的树的高度

完整代码:

public class QuickUnion {
    private int[] id;
    private int count;

    publicQuickUnion(int N) {
        count = N;
        id = new int[N];
        for(int i = 0; i < N; i++) id[i] = i;
    }

    public int getCount() {
        return count;
    }

    public boolean connected(int p, int q) {
        return find(p) == find(q);
    }

    public int find(int p) {
        while(p != id[p]) p = id[p];
        return p;
    }

    public void union(int p, int q){
        int pRoot = find(p);
        int qRoot = find(q);

        if(pRoot == qRoot) return;

        id[pRoot] = qRoot;
        count--;
    }
}

再次优化

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

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

相关文章

大学生简单抗击疫情静态HTML网页设计作品 DIV布局疫情感动人物介绍网页模板代码 DW学生抗疫逆行者网站制作成品下载

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

vTESTstudio入门到精通 - vTESTstudio工具栏介绍_Home

继上篇介绍File功能模块之后&#xff0c;今天我们来介绍vTESTstudio工程使用过程的种的另外一个重要的工具栏Home&#xff0c;这块将是我们使用vTESTstudio编程中使用最多的一个功能模块。话不多说&#xff0c;下面我们就来一一介绍该功能栏能在我们编程的时候做哪些事情。 2、…

网关服务限流熔断降级【Gateway+Sentinel】

目录 第一步&#xff1a;启动sentinel-dashboard控制台 第二步&#xff1a;在网关服务中引入sentinel依赖 第三步&#xff1a;在网关服务application.yml中配置sentinel 第四步&#xff1a;通过网关进入服务 再进入sentinel控制台查看链路情况 第一步&#xff1a;启动sen…

一个简单的dw网页制作作业,学生个人html静态网页制作成品代码——怪盗基德动漫主题网页成品(15页)

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 ⚽精彩专栏推荐&#x1…

【mmdetection系列】mmdetection之evaluate评测

1.configs 还是以yolox为例&#xff0c;配置有一项evaluation。用于配置评估是用什么评价指标评估。 https://github.com/open-mmlab/mmdetection/blob/master/configs/yolox/yolox_s_8x8_300e_coco.py#L151 max_epochs 300 num_last_epochs 15 interval 10evaluation di…

LVS 负载均衡

LVS 负载均衡 本篇主要介绍一下 lvs 是什么 以及它的 nat 模式的搭建 配合nginx来演示 1.概述 LVS 是 Linux Virtual Server 的简写 (Linux 虚拟服务器 ), 是由章文嵩博士主导, 它虚拟出一个服务器集群,然后进行负载均衡的项目, 目前LVS 已经被集成到Linux内核模块中了, 外部请…

直播弹幕系统(三)- 直播在线人数统计

直播弹幕系统&#xff08;三&#xff09;- 直播在线人数统计前言一. 在线人数统计功能实现1.1 Redis整合1.2 在线人数更新1.3 演示前言 上一篇文章整合RabbitMQ进行消息广播和异步处理 写完了消息的广播、削峰、异步处理业务逻辑等操作。完成了实时共享功能。 不过写到后面发…

Netcat介绍及安装使用

目录 介绍 Linux 安装 Windows安装 1.下载安装包 2.解压安装包 3.安装路径加入系统变量 Netcat命令参数 使用Netcat互相通信 1.创建一个服务端 2.创建一个客户端&#xff08;连接服务端&#xff09; 介绍 Netcat 是一款简单的Unix工具&#xff0c;使用UDP和TCP协议。…

七、Docker 安装Tomcat(流程、注意点、实操)

1、从中央仓库搜索tomcat 命令:docker search tomcat 也可以从官网查找,地址:Docker Hub 2、从中央仓库拉取tomcat 命令:docker pull tomcat:8.0 这里我们选择8.0 版本tomcat 3、查看镜像 命令:docker images 4、运行镜像 命令:docker run -d

如何从内存卡恢复丢失的数据?简单内存卡(SD卡)数据恢复方法分享

SD卡&#xff0c;也就是内存卡&#xff0c;在日常使用中有着体积小、存储量大的优点&#xff0c;被我们用来存储一些重要的数据。相机是使用SD卡的场景之一。目前大多数相机都使用SD卡来存储相关数据&#xff0c;这不仅是因为SD容量的优势&#xff0c;而且其运行速度也比较快&a…

苹果手机有什么好玩的app推荐

creativeclock 苹果手机有什么好玩的app推荐&#xff0c;iPhone时钟app推荐下载。 An elegant clock application that contains various creative clock styles and widgets. FlipClock, PolarClock, DigitalClock, RouletteClock, AnalogClock … and so on. view on Appsto…

Matplotlib学习笔记(第二章 2.1.5 图形的绘制过程)

本教程旨在展示使用Matplotlib的单个可视化的开始、中间和结束。 我们将从一些原始数据开始&#xff0c;最后保存一个定制的可视化图形。 在此过程中&#xff0c;我们尝试使用Matplotlib来突出一些整洁的特性和最佳实践。 注意&#xff1a;本教程基于克里斯莫菲特这篇优秀的博…

【图像去噪】鲁棒PCA图像去噪【含Matlab源码 463期】

⛄一、图像去噪及滤波简介 1 图像去噪 1.1 图像噪声定义 噪声是干扰图像视觉效果的重要因素&#xff0c;图像去噪是指减少图像中噪声的过程。噪声分类有三种&#xff1a;加性噪声&#xff0c;乘性噪声和量化噪声。我们用f(x,y&#xff09;表示图像&#xff0c;g(x,y&#xff0…

jmeter性能测试-Arrivals 线程组解释

&#x1f4cc; 博客主页&#xff1a; 程序员二黑 &#x1f4cc; 专注于软件测试领域相关技术实践和思考&#xff0c;持续分享自动化软件测试开发干货知识&#xff01; &#x1f4cc; 公号同名&#xff0c;欢迎加入我的测试交流群&#xff0c;我们一起交流学习&#xff01; 目录…

Go项目目录结构该怎么写?

原文地址&#xff1a;Go项目目录结构该怎么写&#xff1f; Go 目录 /cmd 项目的主干。 每个应用程序的目录名应该与想要的可执行文件的名称相匹配(例如&#xff0c;/cmd/myapp)。 不要在这个目录中放置太多代码。如果认为代码可以导入并在其他项目中使用&#xff0c;那么它…

Python入门自学到精通需要看哪些书籍?

Python语言在近几年可以算得上如日中天&#xff0c;越来越火爆的同时&#xff0c;学习Python的人也越来越多了。对于不同基础的学习者来讲&#xff0c;学习的重点和方式也许会有差别&#xff0c;但是基础语法永远都是重中之重。在牢牢掌握基础知识的前提下&#xff0c;我们才能…

SAP ABAP 利用弹窗(POPUP)实现屏幕(DIALOG)快速开发

SAP ABAP 利用弹窗&#xff08;POPUP&#xff09;实现屏幕&#xff08;DIALOG&#xff09;快速开发 引言&#xff1a; 在 ABAP 开发中经常用到屏幕&#xff08;DIALOG&#xff09;开发&#xff0c;这通常都比较耗时。按复杂度可以分成复杂和简单两类屏幕开发&#xff0c;复杂的…

linux(乌班图)开发环境搭建

乌班图远程连接方法&#xff1a;安装openssh-server 和openssh-clientsudo apt-get -y install openssh-server openssh-client 设置允许root用户进行远程连接 方法一&#xff1a; /etc/ssh/sshd_config里面添加PermitRootLogin yes #重启 service ssh restart方法二&#xff1…

Pandas小白入门(一)---将value_counts的结果转为DataFrame

文章目录代码示例工作原理rename_axisreset_index各函数对于DataFrame下的应用其他应用quantile结果转为DataFrame代码示例 value_counts的结果是一个series&#xff0c;其index为原来列的值&#xff0c;value为值的个数。要将其转为DataFrame需要两个函数rename_axis和reset_…

为什么每个程序员都必须写博客

工作了好几年了&#xff0c;一直没写过技术类的博客&#xff0c;最近才开始尝试写一些技术类的博客。通过写博客的这段时间发现&#xff0c;写博客能够帮助我们快速成长已经提高我们学习的积极性&#xff0c;本文将和大家详细说说程序员写博客的好处。 &#x1f680; 一、加深对…