首页 > 其他分享 >并查集

并查集

时间:2023-12-14 22:13:13浏览次数:22  
标签:查集 元素 father find 集合 节点

并查集

并查集是一种采用树形结构存储的集合,可以高效的查找两个元素是否在一个集合当中以及合并两个集合。这里的树形结构并非仅指二叉树,而是一个节点可以有多个孩子。

对于一个并查集的节点,它可以有两个元素,一个存储该节点的数据,另一个用来指向其父节点。当然当我们所存储的元素为1-n的连续整数时,数组下标就可以表征数据,而数组元素存储其父节点下标即可。比如这道题合并集合

并查集的核心操作就是查找一个元素的根节点,也就是找到该集合中没有父节点的那个节点。由于这个节点在该集合中唯一,且通过该集合中的任意一个节点都可以寻找到该节点,因此一个集合的根节点可以表征这个集合。
image
如上图,集合1有4个元素[1,2,3,4],集合2有5个元素[5,6,7,8,9]。可以看到,集合1的根节点为值为1的点,集合2的根节点为值为5的点

  • 要判断某两个元素是否在一个集合当中,只需要向上找到它们的根节点,若根节点相同,则属于一个集合,反之。
  • 若要合并某两个元素所在的集合,也只要找出他们的根节点,由并查集的特性,根节点相同即为同一集合,那么我们只需要将其中一个集合的根节点的父节点设置为另一个集合的根节点即可。

为区分根节点,我们将根节点的父节点值设为-1或者指向自身。

下面给出并查集找根节点的函数,find函数的实现

int find(int u)
{
	while (father[u] != -1) u = father[u];
	//这里使用-1来标记根节点,当然初始化为Father[i] = i ,判断条件为Father[u] != u也可
	return u;
}

find函数实现逻辑很简单,就是迭代的向上找出节点的根节点。

可以看出,find函数查找出根节点的平均时间复杂度跟存储并查集的树的高度或者说层数有关,为O(logn),当极端情况下,每一层仅有一个元素时,查找时间复杂度退化到O(n)。有没有什么方法可以改进呢?
答案是肯定的。我们将find函数中的迭代部分

while(father[u] != -1)u = father[u];
return u;

替换为

if(father[u] != -1) return father[u] = find(father[u]);
else	return u;//找到根节点,返回根节点
//当采用father[i] = i标记时,也可以这样写
if(father[u] != u) father[u] = find(father[u]);
return father[u];

这样的话可以知道,当整个过程递归到最底层时开始返回,而返回的值一直是根节点的下标(两种写法都是),也就是说,在查找的同时,我们将这个集合的所有节点都连接掉的了根节点上,可以示意为下图
image
这样的话,原先的多层结构经过一次find操作就变成了一层。因此这样优化之后,find的时间复杂度可以近似为O(1)。这种优化的方法叫做路径压缩

标签:查集,元素,father,find,集合,节点
From: https://www.cnblogs.com/CrescentWind/p/17900126.html

相关文章

  • (来一套)JavaScript并查集模板
    code: classUnionFind{constructor(n){this.parent=Array.from({length:n},(_,i)=>i);this.size=newArray(n).fill(1);this.cnt=n;}findset(x){if(this.parent[x]===x){returnx......
  • 带权并查集
    对于种类并查集主要是考虑清楚到根节点距离分为几类,每一类的意义有的题目相出d数组的含义才能想到用带权并查集//find函数需要变化intfind(intx){if(p[x]!=x){introot=find(p[x]);d[x]+=d[p[x]];p[x]=root;}retur......
  • 并查集基础版
    并查集(byd打到一半没保存直接关了乆乆乆)并查集是一种数据结构,它可以用一个优秀的时间复杂度(路径压缩后接近\(O(1)\))来维持多个集合之间的关系,并进行查找和合并。查找操作我们可以定义一个并查集数组\(p[i]=j\)表示\(i\)的父亲(并查集实际是把一个一个的集合看做树来处理)是\(j......
  • 不带权并查集——jly
    structDSU{vector<int>f,siz;DSU(){}DSU(intn){init(n);}voidinit(intn){f.resize(n);std::iota(f.begin(),f.end(),0);siz.assign(n,1);}intfind(intx){......
  • 第 132 场周赛——质数小结论,并查集配Floyd
    https://www.acwing.com/activity/content/competition/problem_list/3648/B题收获:1.利用题目告诉的结论:1e9范围质数之差小于3002.一个数不被2-a的任何数整除等价于他的最小质因子需要大于ac题:初步宏观思路:不难想到用并查集维护类别,只需将每一个类缩成一个点,由于最多只有500......
  • 并查集汇总
    并查集简介并查集是一种可以动态维护若干个不重叠的结合,并支持合并与查询的数据结构并查集是一种树状的数据结构,可以用于维护传递关系以及联通性。并查集有两种操作:find:查询一个元素属于哪个集合merge:合并两个集合模板find函数intfind(intx){ if(x==fa[x]) ret......
  • 【模板】并查集 (洛谷P3367)
    1#include<bits/stdc++.h>2usingnamespacestd;3template<classT>4inlinevoidread(T&s)5{6s=0;7intw=1;8charch=getchar();9while(ch<'0'||ch>'9')10{11......
  • 带权并查集
    很新奇啊这个东西。用来解决形如\(x_i-x_j=y\)系列方程组有无解的问题。思路很简单,\(dis_i\)代表从\(i\)的祖先与\(i\)之间的差值。这样能秒算出方程组中任意两个点的差值。本质是每次把两个方程组合并。找祖先部分:intfindpa(intx){ if(fa[x]!=x){ int......
  • 并查集学习笔记
    简介这里引用OI-wiki上的内容:并查集是一种用于管理元素所属集合的数据结构,实现为一个森林,其中每棵树表示一个集合,树中的节点表示对应集合中的元素。顾名思义,并查集支持两种操作:合并(Union):合并两个元素所属集合(合并对应的树)查询(Find):查询某个元素所属集合(查询对应的树的根节点),......
  • 并查集
    多少张桌子时间限制:2000/1000MS(Java/其他)内存限制:65536/32768K(Java/其他)问题描述今天是伊格内修斯的生日。他邀请了很多朋友。现在是晚餐时间。伊格内修斯想知道他至少需要多少张桌子。你必须注意,并不是所有的朋友都认识对方,所有的朋友都不想和陌生人呆在一起。这个问题的......