【数据结构】 并查集 + 路径压缩与按秩合并 python

目录

  • 前言
  • 模板
  • 朴素实现
  • 路径压缩
  • 按秩合并
    • 按树高为秩
    • 按节点数为秩
  • 总结


前言


并查集的基本实现通常使用森林来表示不同的集合,每个集合用一棵树表示,树的每个节点有一个指向其父节点的指针。
如果一个节点是它自己的父节点,那么它就是该集合的代表(称为根节点)。



模板


P3367 【模板】并查集 https://www.luogu.com.cn/problem/P3367


题目描述

如题,现在有一个并查集,你需要完成合并和查询操作。

输入格式

第一行包含两个整数 N , M N,M N,M ,表示共有 N N N 个元素和 M M M 个操作。

接下来 M M M 行,每行包含三个整数 Z i , X i , Y i Z_i,X_i,Y_i Zi,Xi,Yi

Z i = 1 Z_i=1 Zi=1 时,将 X i X_i Xi Y i Y_i Yi 所在的集合合并。

Z i = 2 Z_i=2 Zi=2 时,输出 X i X_i Xi Y i Y_i Yi 是否在同一集合内,是的输出
Y ;否则输出 N

输出格式

对于每一个 Z i = 2 Z_i=2 Zi=2 的操作,都有一行输出,每行包含一个大写字母,为 Y 或者 N

**样例输入 **

4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4

样例输出

N
Y
N
Y

提示

对于 15 % 15\% 15% 的数据, N ≤ 10 N \le 10 N10 M ≤ 20 M \le 20 M20

对于 35 % 35\% 35% 的数据, N ≤ 100 N \le 100 N100 M ≤ 1 0 3 M \le 10^3 M103

对于 50 % 50\% 50% 的数据, 1 ≤ N ≤ 1 0 4 1\le N \le 10^4 1N104 1 ≤ M ≤ 2 × 1 0 5 1\le M \le 2\times 10^5 1M2×105

对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 2 × 1 0 5 1\le N\le 2\times 10^5 1N2×105 1 ≤ M ≤ 1 0 6 1\le M\le 10^6 1M106 1 ≤ X i , Y i ≤ N 1 \le X_i, Y_i \le N 1Xi,YiN Z i ∈ { 1 , 2 } Z_i \in \{ 1, 2 \} Zi{1,2}


朴素实现


code:

# 在集合中查找元素的根节点
def find(x):
    if x != pre[x]:
        return find(pre[x])
    return x


# 将两个集合合并为一个集合
def union(x, y, pre):
    x_root = find(x)
    y_root = find(y)
    pre[x_root] = y_root


n, m = map(int, input().split())
pre = [0] * (n + 1)
for i in range(n):
    pre[i] = i  # 初始化
for _ in range(m):
    op, x, y = map(int, input().split())
    if op == 1:
        union(x, y, pre)
    else:
        if find(x) == find(y):
            print('Y')
        else:
            print('N')


在这里插入图片描述


事实证明:我们需要进行时间上的优化



路径压缩


由于在查询过程中只关心根结点是什么,所以我们可以在在集合在查找元素的同时,把集合中所有的元素都直接指向根节点,减少查找的时间


示例code

def find(x):
    if pre[x] != x:
        pre[x] = find(pre[x])  # 在回溯时进行路径压缩
    return pre[x]

tips:可能会破坏原本的结构



按秩合并


之前我们在合并时,是随机合并两个集合
虽然都能得到正确的结果,但存在时间复杂度的差异
怎样降低时间复杂度呢?
通过按秩合并(启发式合并)

秩”可以理解为树的高度树的节点数 这两种方式
在合并两棵树时,总是把较矮的树挂到较高的树上,节点较小的树挂在节点较多的树上
这种策略有助于保持树的平衡,从而降低查找操作的时间复杂度。

怎么实现?用一个数组记录每个集合的高度或节点数



按树高为秩

示例:

# 将两个集合合并为一个集合
def union(x, y):
    x_root = find(x)
    y_root = find(y)
    if x_root != y_root:
        # 谁高,谁就作为根节点
        if rank[x_root] > rank[y_root]:
            pre[y_root] = x_root
        elif rank[x_root] < rank[y_root]:
            pre[x_root] = y_root
        else:
            pre[x_root] = y_root
            rank[y_root] += 1
# 合并是把小的树直接接到根节点上,所以只有两颗树的高度相等的时候合并后高度才会增加


按节点数为秩

示例:

# 将两个集合合并为一个集合
def union(x, y):
    x_root = find(x)
    y_root = find(y)
    if x_root != y_root:
        # 谁的节点数多,谁就作为根节点
        if size[x_root] > size[y_root]:
            pre[y_root] = x_root
            size[x_root] += size[y_root]
        else:
            pre[x_root] = y_root
            size[y_root] += size[x_root]


题解code1(路径压缩+按节点数为秩合并):

# 在集合中查找元素的根节点
def find(x):
    global pre
    if pre[x] != x:
        pre[x] = find(pre[x])  # 在回溯时进行路径压缩
    return pre[x]


# 将两个集合合并为一个集合
def union(x, y):
    global pre, size
    x_root = find(x)
    y_root = find(y)
    if x_root != y_root:
        # 谁的节点数多,谁就作为根节点
        if size[x_root] > size[y_root]:
            pre[y_root] = x_root
            size[x_root] += size[y_root]
        else:
            pre[x_root] = y_root
            size[y_root] += size[x_root]


n, m = map(int, input().split())
pre = list(range(n + 1))  # 初始化pre数组
size = [1] * (n + 1)  # 初始化size数组
for _ in range(m):
    op, x, y = map(int, input().split())
    if op == 1:
        union(x, y)
    else:
        if find(x) == find(y):
            print('Y')
        else:
            print('N')

路径压缩与按节点大小合并完全兼容


题解code2(按树高为秩合并):

# 在集合中查找元素的根节点
def find(x):
    global pre
    if pre[x] != x:
        pre[x] = find(pre[x])  # 在回溯时进行路径压缩
    return pre[x]

# 将两个集合合并为一个集合
def union(x, y):
    global pre, rank
    x_root = find(x)
    y_root = find(y)
    if x_root != y_root:
        # 谁高,谁就作为根节点
        if rank[x_root] > rank[y_root]:
            pre[y_root] = x_root
        elif rank[x_root] < rank[y_root]:
            pre[x_root] = y_root
        else:
            pre[x_root] = y_root
            rank[y_root] += 1
# 合并是把小的树直接接到根节点上,所以只有两颗树的高度相等的时候合并后高度才会增加


n, m = map(int, input().split())
pre = list(range(n + 1))  # 初始化pre数组
rank = [1] * (n + 1)  # 初始化rank数组
for _ in range(m):
    op, x, y = map(int, input().split())
    if op == 1:
        union(x, y)
    else:
        if find(x) == find(y):
            print('Y')
        else:
            print('N')

路径压缩不完全与按树高合并兼容,因为路径压缩可以改变树的高度。


总结


并查集(Union-Find 或 Disjoint Set Union, DSU)是一种数据结构,主要用于处理一些不相交集合的合并及查询问题。


如果有更多问题或需要进一步的帮助,可以在评论区留言讨论哦!
如果喜欢的话,请给博主点个关注 谢谢

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Flutter android debug 编译报错问题。插件编译报错

下面相关内容 都以 Mac 电脑为例子。 一、问题 起因&#xff1a;&#xff08;更新 Android studio 2024.2.2.13、 Flutter SDK 3.27.2&#xff09; 最近 2025年 1 月 左右&#xff0c;我更新了 Android studio 和 Flutter SDK 再运行就会出现下面的问题。当然 下面的提示只是其…

CSAPP学习:前言

前言 本书简称CS&#xff1a;APP。 背景知识 一些基础的C语言知识 如何阅读 Do-做系统 在真正的系统上解决具体的问题&#xff0c;或是编写和运行程序。 章节 2025-1-27 个人认为如下章节将会对学习408中的操作系统与计算机组成原理提供帮助&#xff0c;于是先凭借记忆将其简单…

动态规划DP 数字三角型模型 方格取数(题目详解+C++代码实现)

方格取数 原题链接 AcWing 1027. 方格取数 题目描述 设有 NN 的方格图&#xff0c;我们在其中的某些方格中填入正整数&#xff0c;而其它的方格中则放入数字0。 如下图所示&#xff1a; 某人从图中的左上角 A 出发&#xff0c;可以向下行走&#xff0c;也可以向右行走&…

【Linux】20.基础IO(2)

文章目录 2. 理解文件系统2.1 inode2.2 如何理解目录2.3 硬链接2.4 软链接2.5 硬链接和软链接的区别 2. 理解文件系统 2.1 inode 我们使用ls -l的时候看到的除了看到文件名&#xff0c;还看到了文件元数据。 ydk_108iZuf68hz06p6s2809gl3i1Z:~/108/lesson20$ ll total 8 drw…

read+write实现:链表放到文件+文件数据放到链表 的功能

思路 一、 定义链表&#xff1a; 1 节点结构&#xff08;数据int型&#xff09; 2 链表操作&#xff08;创建节点、插入节点、释放链表、打印链表&#xff09;。 二、链表保存到文件 1打开文件 2遍历链表、写文件&#xff1a; 遍历链表,write()将节点数据写入文件。…

图漾相机-ROS2-SDK-Ubuntu版本编译(新版本)

官网编译文档链接&#xff1a; https://doc.percipio.xyz/cam/latest/getstarted/sdk-ros2-compile.html 国内gitee下载SDK链接&#xff1a; https://gitee.com/percipioxyz 国外github下载SDK链接&#xff1a; https://github.com/percipioxyz 1.Camport ROS2 SDK 介绍 1.1 …

C# 添加、替换、提取、或删除Excel中的图片

在Excel中插入与数据相关的图片&#xff0c;能将关键数据或信息以更直观的方式呈现出来&#xff0c;使文档更加美观。此外&#xff0c;对于已有图片&#xff0c;你有事可能需要更新图片以确保信息的准确性&#xff0c;或者将Excel 中的图片单独保存&#xff0c;用于资料归档、备…

智能风控 数据分析 groupby、apply、reset_index组合拳

目录 groupby——分组 本例 apply——对每个分组应用一个函数 等价用法 reset_index——重置索引 使用前​编辑 注意事项 groupby必须配合聚合函数、 关于agglist 一些groupby试验 1. groupby对象之后。sum&#xff08;一个列名&#xff09; 2. groupby对象…

浅析百度AOI数据与高德AOI数据的差异性

目录 前言 一、AOI属性数据 1、百度AOI数据 2、高德AOI数据 二、AOI矢量边界 1、百度AOI空间范围 2、高德AOI空间范围 三、数据获取频次和难易程度 1、接口限制 2、数据转换成本 四、总结 前言 在当今数字化时代&#xff0c;地理信息数据的精准性和丰富性对于城市规划…

通过亚马逊云科技Bedrock打造自定义AI智能体Agent(上)

大家对于智能体代理Agent一定已经非常熟悉&#xff0c;自主代理&#xff08;Autonomous Agents&#xff09; 目前在AI行业极其热门并具有巨大的潜力&#xff0c;能够显著提升开发者日常的工作效率、自动化日常琐碎、重复性任务&#xff0c;并生成全新的内容。Agent可以理解用户…

汇编的使用总结

一、汇编的组成 1、汇编指令&#xff08;指令集&#xff09; 数据处理指令: 数据搬移指令 数据移位指令 位运算指令 算术运算指令 比较指令 跳转指令 内存读写指令 状态寄存器传送指令 异常产生指令等 2、伪指令 不是汇编指令&#xff0c;但是可以起到指令的作用&#xff0c;伪…

S4 HANA定义税码(FTXP)

本文主要介绍在S4 HANA OP中S4 HANA定义税码相关设置。具体请参照如下内容&#xff1a; 定义税码(FTXP) 以上界面是根据国家的“定价过程”确定的。蓝色的行项目表示目前已经激活的行项目。 不可抵扣进项税一般用于采购业务中&#xff0c;因此用在进项税码中。 消费税和营业…

Git进阶笔记系列(01)Git核心架构原理 | 常用命令实战集合

读书笔记&#xff1a;卓越强迫症强大恐惧症&#xff0c;在亲子家庭、职场关系里尤其是纵向关系模型里&#xff0c;这两种状态很容易无缝衔接。尤其父母对子女、领导对下属&#xff0c;都有望子成龙、强将无弱兵的期望&#xff0c;然而在你的面前&#xff0c;他们才是永远强大的…

多级缓存(亿级并发解决方案)

多级缓存&#xff08;亿级流量&#xff08;并发&#xff09;的缓存方案&#xff09; 传统缓存的问题 传统缓存是请求到达tomcat后&#xff0c;先查询redis&#xff0c;如果未命中则查询数据库&#xff0c;问题如下&#xff1a; &#xff08;1&#xff09;请求要经过tomcat处…

场景设计学习-积分系统

场景设计-积分系统 1.概念和规则 积分&#xff1a;用户在网站的各种交互行为都可以产生积分&#xff0c;积分值与行为类型有关天梯榜&#xff1a;按照每个用户的总积分排序得到的排行榜&#xff0c;称为天梯榜。排名靠前的有奖励。天梯榜每个自然月为一个赛季&#xff0c;月初…

ML基础3-sklearn中的1个简单的分类器例子

Scikit-learn&#xff08;通常缩写为sklearn&#xff09;是一个流行的Python机器学习库&#xff0c;用于数据挖掘和数据分析任务。它建立在NumPy、SciPy和matplotlib等科学计算/可视化库的基础上&#xff0c;提供了丰富的工具和算法&#xff0c;用于处理各种机器学习问题&#…

The Simulation技术浅析(二):模型技术

一、物理模型(Physical Models) 1. 概述 物理模型基于物理定律和原理,通过模拟现实世界中物理系统的行为和相互作用来构建模型。物理模型通常用于工程、物理和化学等领域,用于预测系统在不同条件下的表现。 2. 关键技术 力学定律:例如牛顿运动定律,用于模拟物体的运动…

006 mybatis关联查询(一对一、一对多)

文章目录 一对一查询SQL语句方法一&#xff1a;resultType方法二&#xff1a;resultMap创建扩展po类Mapper映射文件Mapper接口测试代码小结 一对多查询SQL语句修改po类Mapper映射文件Mapper接口测试代码 注意&#xff1a;因为一个订单信息只会是一个人下的订单&#xff0c;所以…

linux asio网络编程理论及实现

最近在B站看了恋恋风辰大佬的asio网络编程&#xff0c;质量非常高。在本章中将对ASIO异步网络编程的整体及一些实现细节进行完整的梳理&#xff0c;用于复习与分享。大佬的博客&#xff1a;恋恋风辰官方博客 Preactor/Reactor模式 在网络编程中&#xff0c;通常根据事件处理的触…

渗透测试之WAF规则触发绕过规则之规则库绕过方式

目录 Waf触发规则的绕过 特殊字符替换空格 实例 特殊字符拼接绕过waf Mysql 内置得方法 注释包含关键字 实例 Waf触发规则的绕过 特殊字符替换空格 用一些特殊字符代替空格&#xff0c;比如在mysql中%0a是换行&#xff0c;可以代替空格 这个方法也可以部分绕过最新版本的…