首页 > 其他分享 >并查集知识梳理

并查集知识梳理

时间:2023-07-22 20:55:06浏览次数:26  
标签:知识 parent int 查集 合并 find 上级 梳理

并查集

目录

并查集的定义

  1. 并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。
  2. 并查集通常包含两种操作:
    查找(Find):查询两个元素是否在同一个集合中
    合并(Union):把两个不相交的集合合并为一个集合
  3. 组词解释法:并:合并,查:查找,集:集合。连成一句话来说就是用来合并、查找的集合

并查集的思想

开始所有点上级都为它本身

下标 0 1 2 3 4 5
上级 0 1 2 3 4 5

把2,3合并到0(树1),

把4,5合并到1(树2)

下标 0 1 2 3 4 5
上级 0 1 0 0 1 1

把1合并到0(合并树1,树2)

下标 0 1 2 3 4 5
上级 0 0 0 0 1 1

朴素并查集的代码

(1)初始化

int parent[105];//记录自己的上级
void init(int n) {
    for(int i = 0;i < n;i ++) {
        parent[i] = i;//将自己的上级赋值为自己
    }
}

现在所有点上级都为它本身

下标 0 1 2 3 4 5
上级 0 1 2 3 4 5

(2)查找

int find(int x) {
    if(parent[x] == x) {//判断自己是不是自己的上级
        return x;
    } else {
        return find(parent[x]);//如果不是,查找自己上级的上级
    }
}

查找时要一层一层的访问自己的上级,自己到自己是自己的上级为止

下标 0 1 2 3 4 5
上级 0 0 0 0 1 1

举例:访问4的上级

路径:4->1,1->0

(3)合并

//把j合并到i中去
void merge(int i,int j) {
    parent[find(j)]=find(i);//把j的上级设为i的上级
}

下标 0 1 2 3 4 5
上级 0 1 0 0 1 1

下标 0 1 2 3 4 5
上级 0 0 0 0 1 1

将1合并到0

路径压缩

作用:

提高并查集效率

举一个极端的例子:

假设我们一共有1e9个点,如图一直排列下去

那么我们查找就需要o(n)的复杂度(就会爆炸)

但办法是人想出来的,记住并查集是一个树形结构,然后就有了下图的优化

这样一来时间复杂度就只有o(logn)了(十分的诱人呢)

接下来是上代码时间

(1)查找代码

版本一:

int find (int x) {
    if (parent[x] == x) {
       return x; 
    } else {
        parent[x] = find(parent[x]);
        return parent[x];
    }
}

版本二:

int find (int x) {
    return x == parent[x] ? x : (parent[x] = find(parent[x]));
}

(2)路径压缩完整代码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100;
int parent[MAXN];
void init (int n) {//初始化
    for (int i = 1;i <= n;i ++){
        parent[i] = i;
    }
}
int find (int x) {//查找
    if (parent[x] == x) {
       return x; 
    } else {
        parent[x] = find(parent[x]);
        return parent[x];
    }
}
void merge (int i,int j) {//合并
    parent[j] = find(i);
}
int main() {
    return 0;
}

按秩合并

思想

如果现在要合并两一棵树,那么我们应该怎么去合并最优呢?

是从右边到左边?还是从左边到右边?谁是合并后的根节点?

显然这种情况下,我们有两种合并方法:

方法一:

方法二:

我们通过路径压缩知道,深度越浅时间复杂度的上限越小

所以,明显方法二才是最优解

实现

(1)初始化

void init(int n) {
    for(int i = 0;i < n;i ++) {
        parent[i] = i;
        rank[i] = 1;//rank用来记录深度,开始一为一棵树,所以赋值为1
    }
}

(2)合并

void merge (int i,int j) {//合并
    int x = find(i),y = find(j);
    if(rank[x] < rank[y]) {//x作为根节点和y作为根节点的子树的深度比较
        parent[x] = y;//小于则把x合并到y
    } else {
        parent[y] = x;//大于则把y合并到x
    }
    if(rank[x] == rank[y] && x != y) {
        rank[x] ++;//如果两棵树深度相同,那么rank[x] + 1;
    }
}

标签:知识,parent,int,查集,合并,find,上级,梳理
From: https://www.cnblogs.com/L-1115/p/17574225.html

相关文章

  • 并查集知识点梳理
    并查集目录并查集并查集的定义并查集的思想朴素并查集的代码(1)初始化(2)查找(3)合并路径压缩(1)查找代码(2)路径压缩完整代码按秩合并思想实现(1)初始化(2)合并并查集的定义并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。并查集通常包含两种操作:查找(Find):查询两个......
  • 最全linux基础知识
    linux基础知识 [root@localhost~]#各位置表示什么意识root:表示用户名(现在的用户是root切换为test便是张三)localhost:表示主机名(当前主机名切换为别的主机就是别的主机名) ~:家目录(表示当所在的目录切换到etc下便是etc)#:管理员用户切换为$:普通用户关机命令:1,h......
  • 低功耗蓝牙BLE的知识点记录
     低功耗蓝牙协议的各层可以用上图表示其中最重要的是GATT和GAP。 两个重要角色:profile和protocolProfile:确保蓝牙装置应用的互通性,由SIG蓝牙技术联盟定义的规范Protocol:针对传输的封包格式、绕行路径、多工机制、编码解码、设备协定层之间横向的资料传输 低......
  • x86架构BIOS攻击面梳理与分析
    x86架构BIOS攻击面梳理与分析之前的一份学习笔记,主要整理了一下x86架构下BIOS的一些攻击面,BootKit部分还没有搬上来。可能有一些理解存在疏漏的地方,还请看官老爷斧正。调研目标一、梳理安全启动的基本流程经历的过程软硬件层面需要完成的工作二、梳理攻......
  • java 检查集合长度
    Java检查集合长度的实现方法概述在Java开发中,我们经常需要检查集合的长度,以便判断集合中是否包含足够的元素或者进行其他操作。本文将介绍一个简单的方法来实现Java检查集合长度的功能。实现步骤下面是实现Java检查集合长度的步骤,可以用表格形式展示:步骤描述......
  • 数位 DP - 知识点梳理
    本质上是一种基于数位的线性DP。通常用于区间统计问题。当暴力枚举会超时,数位DP可以对区间的值进行按位求解,有时使用位值原理,把每位上相同的数一起求解,降低时间复杂度,有时会用到高位优先的贪心思想。实现LuoguP4124[CQOI2016]手机号码这就是一个区间统计问题。如果暴力......
  • 状态压缩 DP - 知识点梳理
    状态压缩DP,或状压DP,是对状态的一种优化。相比于普通DP,通过将高维状态压缩成一个数,减少了维度,并使维度更易于存储与维护。同时这样与bitset一样利用了计算机在\(O(1)\)内处理位运算的能力,大幅度优化了时间复杂度。一般当题目中的状态由多个\(0\)/\(1\)组成,数量不一定,且......
  • 知识诅咒
    知识诅咒(TheCurseofKnowledge)知识诅咒什么是知识诅咒知识诅咒,指一旦我们自己知道了某样东西,就很难想象不知道它的时候是什么样子。我们的知识“诅咒”了我们。这让我们和他们分享知识时变得困难,因为无法还原听众的心境。例如,我们对自己开发的产品极为熟悉,于是理所当然的......
  • 专属于“电脑族”的护眼小知识
    对于成年人,大部分工作方式已经离不开电脑,这是无可奈何的事情,但是这里有一份专属于你的护眼知识,让在屏幕前的你,了解如何缓解眼疲劳。首先,由于长时间注视电脑屏幕,注意力比较集中,从而眨眼次数减少,使眼睛不能得到泪液充分的滋润,从而导致眼睛干涩、疲劳等,这属于用眼过度,分析完原因......
  • python小知识
    前言一些小知识正文format格式化的转义 将abc_{i}_{j}转换为abc_1_2展开代码s='abc_{i}_{j}'n={'i':1,'j':2}print(s.format_map(n))print(s.format(**n))fork,vinn.items():s=s.replace(f'{{{k}}}',f'{v}')......