并查集-- 一种路径压缩实现

news2024/11/26 8:42:13

并查集用于计算图连通分量。

比如回答这样的问题:

  • 社交媒体中,用户A和用户B是否属于同一个圈子里的?
  • 一个城市到另一个城市是否是可达的?

并查集适用于并不需要计算出图上具体的路径,只需要计算是否连通。

public interface UnionFindSet {

    // 节点a 和 节点b 是否连通,可达
    public boolean isConnect(int a, int b);

    // 合并节点a和节点b所属群
    public int union(int a,int b);
}

什么是并查集

为了方便理解,数形结合一下:

通常使用数组来标记所有节点所属的群组,如下图所示,parent[i]代表第i个节点的父亲。

初始状态下,每个节点的父亲节点都是自己,代表自己单独一个组:
在这里插入图片描述

分别将1,2,4合并,6,7合并:

在这里插入图片描述
此时,多了2个大小超过1的树。parent[i] = 1代表属于节点1为祖先的群组。判断两个节点是否属于同一群组,只需要判断父亲是否相同即可。

如何合并两个节点呢? 下面给出一个简单实现:

遍历更新

遍历更新的方式,即遍历parent数组将所有属于群组b的节点的父亲设置为群组a的父亲.

public class UnionFind {

     private final int[] parent;


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

     public boolean isConnected(int a, int b){
         return parent[a] == parent[b];
     }

	 // 遍历`parent`数组将所有属于群组b的节点的父亲设置为群组a的父亲.
     public int union(int a, int b){
         if (parent[a] == parent[b]){
             return parent[a];
         }
         for (int i = 0; i < parent.length; i++) {
             if (parent[i] == parent[b]){
                 parent[i] = parent[a];
             }
         }
         return parent[a];
     }
}

这种方式优点是isConnected非常简单,因为树的深度只有一层,只需要一次引用即可。
但是有一个缺陷,即每次合并都要遍历一遍parent数组,其时间复杂度是O(n).

那么为了优化union操作的性能,可以将父子关系设置成一颗树,树可以很好的优化查询性能,合并时只需要将树根指向另一个树根即可。

使用树优化union操作

在这里插入图片描述

上面这棵树,1,2,3,4属于同一群组,6,7属于同一群组。如果将两个群组合并,只需要将节点6的父亲指向节点3.

因为现在群组关系里,树的深度不再为2,因此需要不断向上回溯,找到树根,复杂度为O(h). h为树高。

回溯操作使用一个新函数find来表示。

  • isConnected操作的复杂度为O(h).
  • union操作的复杂度为O(h)

这个实现牺牲了较小的查询性能,换取union操作较大的性能提升。

但是还会出现一个问题,就是二叉树经常出现的不平衡问题。极端情况下,树会变成一个链表,其复杂度还会降低为O(n)。

那么为了解决这个问题,我们可以压缩路径,即减小树高。


public class UnionFind {

     private final int[] parent;


     public UnionFind(int size){
         parent= new int[size];
         for (int i = 0; i < size; i++) {
             parent[i] = i;
         }
     }
     // 找到树根
     public int find(int a){
         if (parent[a]!=a){
             a = parent[a];
         }
         return a;
     }

     public boolean isConnected(int a, int b){
         return find(a) == find(b);
     }

     public int union(int a, int b){
         int ap = find(a);
         int bp = find(b);
         if (ap == bp){
             return ap;
         }
         parent[bp] = ap; // 直接将群组b的树根父亲设置为群组a的树根。
         return ap;
     }

}

路径压缩

路径压缩的方式有很多种,下面给出一种实现:

在find操作的过程中,将所有属于同一群组的节点的父亲,置为树根节点。很方便的使用递归来实现。


public class UnionFind {

	 // 记录节点的父亲节点
     private final int[] parent;


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

	 // 找到节点的祖先节点
     public int find(int a){
         if (parent[a]!= a){
             parent[a] = find(parent[a]); // 将a节点的父亲直接设置成祖先,压缩路径
         }
         return parent[a]; // 递归结束条件为parent[a]== a,即自己是自己的父亲
     }
     // 祖先节点相同的节点属于同一群组
     public boolean isConnected(int a, int b){
         return find(a) == find(b);
     }

	 // 合并两个节点所属群组
     public int union(int a, int b){
         int ap = find(a);
         int bp = find(b);
         // 属于同一群组则返回
         if (ap == bp){
             return ap;
         }
         // 属于不同群组,则将一个祖先的父亲置为另一个
         parent[ap] = bp;
         return ap;
     }
}

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

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

相关文章

JavaScript 链表

&#xff08;成功的唯一秘诀——坚持最终一分钟。——柏拉图&#xff09; 链表 众所周知&#xff0c;数组的查询比链表快&#xff0c;但插入比链表慢。 这是因为链表是一种动态的数据结构&#xff0c;不同于数组的是&#xff0c;链表分配内存空间的灵活性&#xff0c;它不会像…

解决车载U盘:USB设备未连接 问题

U盘是一种常用的便携式存储设备&#xff0c;用于存储和传输数据。在U盘上使用的文件系统类型决定了它可以支持的文件大小、安全性和其他特性。以下是几种常见的U盘文件系统类型&#xff1a; 1. FAT32:这是U盘上最常用的文件系统类型之一。FAT32文件系统支持的最大文件大小为4GB…

Revit楼板:建筑楼板和结构楼板区别和垫层生成

一、Revit中建筑楼板和结构楼板的区别 Revit中&#xff0c;在我们做项目时楼板是最常见的结构之一&#xff0c;几乎每次都需要使用它。分为建筑楼板和结构楼板&#xff0c;是不是有很多小伙伴就很好奇,为什么分为两种楼板&#xff0c;那么他们是什么时候使用的呢?之间又有何区…

从测试小白成功转型自动化测试,我是如何一步步掌握坚持下来的?

目录 学习自动化测试的初衷 克服困难&#xff0c;掌握自动化测试技能 自动化测试在日常工作中的应用 第一个自动化测试脚本的完成 自动化测试技能带来的机会和挑战 【自动化测试工程师学习路线】 学习自动化测试的初衷 作为一名测试新人&#xff0c;刚进入测试行业的时候…

工业视觉检测的8个技术优势

工业4.0时代&#xff0c;自动化生产线成为了这个时代的主旋律&#xff0c;而工业视觉检测技术也成为其中亮眼的表现&#xff0c;其机器视觉技术为设备提供了智慧的双眼&#xff0c;让自动化的脚步得以加速&#xff01; 在实际的生产应用中&#xff0c;视觉技术方案往往先被着手…

zed2i相机中imu内参的标定及外参标定

zed2i中imu内参的标定 参考&#xff1a; https://blog.csdn.net/weixin_42681311/article/details/126109617 https://blog.csdn.net/weixin_43135184/article/details/123444090 值得注意&#xff0c;imu内参的标定其实不是那么重要&#xff0c;大致上给一个值应该影响不大…

金字塔特征融合

金字塔的三种主要结构 FPN: Feature Pyramid Networks for Object Detection (CVPR 2017) PANet: Path Aggregation Network for Instance Segmentation (CVPR 2018) BiFPN: EfficientDet: Scalable and Efficient Object Detection (CVPR 2020) Deep High-Resolution Repre…

神奇哈哈镜-第14届蓝桥杯省赛Scratch初级组真题第3题

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第132讲。 神奇哈哈镜&#xff0c;本题是2023年5月7日举行的第14届蓝桥杯省赛Scratch图形化编程初级组真题第3题&#…

颜值经济崛起,伽蓝开启采购数字化之旅

今天&#xff0c;数字化转型已成为颠覆性力量&#xff0c;很多行业被裹挟其中&#xff0c;或主动或被动&#xff0c;美妆行业也不例外。 作为国内最大的化妆品企业之一的伽蓝&#xff0c;在过去的几年当中&#xff0c;一直是以 7% 到 10% 的速度快速增长&#xff0c;在此过程中…

计算机组成原理---第二章 习题详解版

(一&#xff09;课内习题 1. &#xff08;二&#xff09;课后练习 1.写出下列各整数的原码、反码和补码表示&#xff08;用8位二进制表示&#xff09;。其中MSB是最高位&#xff08;符号位&#xff09;&#xff0c;LSB是最低位。 &#xff08;1&#xff09;-35 &#…

DVWA之文件包含漏洞

文件包含漏洞原理 1、什么是文件包含 程序开发人员一般会把重复使用的函数写到单个文件中&#xff0c;需要使用某个函数时直接调用此文件&#xff0c;而无需再次编写&#xff0c;这中文件调用的过程一般被称为文件包含。 2、文件包含漏洞 程序开发人员一般希望代码更灵活&a…

自学网络安全【黑客】,一般人我劝你还是算了吧

前言&#xff1a;我是劝一般人算了&#xff0c;看你是一般人还是。。。 一、网络安全学习的误区 1.不要试图以编程为基础去学习网络安全2.不要刚开始就深度学习网络安全3.收集适当的学习资料4.适当的报班学习二、学习网络安全的些许准备 1.硬件选择2.软件选择3.外语能力三、网…

数据结构:双向链表(带头循环)

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下数据结构方面有关双向链表的相关知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a…

时至今日,Linux会开源,也是一种态度

什么是开源&#xff1f;开源通常指开发者公开系统/应用程序源代码。通过对代码进行共享和重用&#xff0c;可以快速开发出高质量、低维护成本的应用程序。这意味着你不再需要花很多时间来学习新技术或编写复杂的代码。 一、Linux永远的神 就拿linux来举例子。 Linux系统的发起…

分享Python采集190个jQuery代码,总有一款适合您

分享Python采集190个jQuery代码&#xff0c;总有一款适合您 Python采集的190个jQuery代码下载链接&#xff1a;https://pan.baidu.com/s/1KxEOw7IfgZJq7yhYBM1nwg?pwdz3r1 提取码&#xff1a;z3r1 可拖拽的谷歌样式纯javascript模态窗口插件 简单实用的轻量级jQuery评分插…

ubuntu系统配置大恒相机驱动并读取ros话题

文章目录 0. 说明1. 安装大恒相机sdk1.1 下载1.2 安装sdk(用于配置ip和调试相机参数)(1) 电脑网卡配置(网卡固定ip)(2)查看相机图像以及配置相机参数 2. 安装ros驱动包(注&#xff1a;大恒相机官方没ros驱动)2.0 正确流程2.1 错误示范2.1 报错1--缺包2.2 报错2--包编译顺序问题…

CnOpenData缺陷产品召回数据

一、数据简介 缺陷产品召回&#xff0c;是指缺陷产品的生产商、销售商、进口商在得知其生产、销售或进口的产品存在可能引发消费者健康、安全问题的缺陷时&#xff0c;依法向职能部门报告&#xff0c;及时通知消费者&#xff0c;设法从市场上、消费者手中收回缺陷产品&#xff…

Python神经网络学习(六)--机器学习--强化学习

前言&#xff1a; 属实是失踪人口回归了。继续神经网络系列。 强化学习&#xff1a; 强化学习也是一个很重要的方向了&#xff0c;很多人用强化学习玩游戏&#xff0c;可能有人觉得强化学习很难&#xff08;包括我&#xff09;&#xff0c;但是我今天用网上流传很广的、很经…

error: static assertion failed: std::atomic requires a trivially copy type

1. 报错信息 编译期错误&#xff0c;gcc version 7.5.0 错误示例代码&#xff1a; #include <atomic> #include <iostream> #include <vector>int main() {std::atomic<std::vector<int>> a; }2. 问题分析 报错信息里明确说了&#xff0c;ato…

商品说明书的翻译,中译英如何翻译效果好?

众所周知&#xff0c;国内产品进入国际市场&#xff0c;商品说明书的翻译是必不可少的&#xff0c;译文必须以准确的语言表达出原文的信息。那么&#xff0c;针对商品说明书翻译&#xff0c;中译英如何翻译效果好&#xff1f; 业内人士指出&#xff0c;很多商品说明书包含有关产…