并查集
c++中的并查集:什么是并查集 并查集有什么用处呢? 如何灵活使用普通的并查集操作呢?
普通并查集 概论:
定义:
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题(即所谓的并、查)。
一般的并查集主要记录节点之间的链接关系,而没有其他的具体的信息,仅仅代表某个节点与其父节点之间存在联系,它多用来判断图的连通性。
图片选自csdn博客
总体来说,他是一种树状数据联系的查询与分配方法。
比如说,我们可以用并查集来判断一个森林中有几棵树、某个节点是否属于某棵树等。
主要构成:
并查集主要由一个整型数组pre[ ]和两个函数find( )、join( )构成。
数组 pre[ ] 记录了每个点的前驱节点是谁,函数 find(x) 用于查找指定节点 x 属于哪个集合,函数 join(x,y) 用于合并两个节点 x 和 y 。
普通并查集的作用:
并查集的主要作用是求连通分支数(如果一个图中所有点都存在可达关系(直接或间接相连),则此图的连通分支数为1;如果此图有两大子图各自全部可达,则此图的连通分支数为2……)
调度分配每一个人对于某一群人的所属关系,帮派的划分,父与子的关系图等等。
就像刚才说的,它用于联系每个数据使之成为一个树状数据。
数据结构的角度来看:
由于我们的重点是在关注两个人是否连通,因此他们具体是如何连通的,内部结构是怎样的,甚至根节点是哪个都不重要。
普通并查集的使用 代码编写:
首先我们要定义一个一维数组 f [maxn](maxn是一个数字,它可以根据题目要求而设定,但是我一般把他设置的很大,避免数据超过数组范围导致段错误,但同时他会消耗分配内存)
这个数组他记录了每个人他本身的数据和他的父级数据,例如f[16] = 6 意思是16号的上级是6号。
如果一个数据的下标是数据本身(例如:f[10] = 10) 那么这个数据就是本树状数据的牢大(最高级的那一位)。
但是这个查询的顺序想必大家也能看出来一点——他是一级一级向上去寻找的,所以过会要讲到的并查集find函数就是这样一个原理。
//local:
int n;
int f[100010];
void init()
{
for(int i =1;i<=n;i++)
{
f[i] = i;
}
}
//后面的main中只需要输入n和调用init()就行.
上述是一个普通并查集的数组初始化,一目了然对吧.
int find(int a)
{
return a ? f[a] == find(a) : a;
}
上述是一个查找首级的并查集寻找函数find(int _a),他的最大作用就是不停的向上摸索上级,直到他找到首级结束,用一个异或运算让他的代码字节量压缩到清晰易懂轻量的形式.
void merge(int a,int b)
{
int fa = find(a);
int fb = find(b);
if(fa != fb) f[fa] = fb;
}
上述是一个普通并查集的合并操作merge(int _a,int _b) 其作用基于find函数上寻找某个节点的首级,然后将一个首级 替换为另一个首级 (也就相当于将这个树状数据尾插到另一个树状数据低下)
板子like this:
P3367 【模板】并查集 - 洛谷 | 计算机科学教育新生态
#include <iostream>
using namespace std;
int n,m;
int z,x,y;
int f[100010];
void init()
{
for(int i = 1;i<=n;i++) f[i] = i;
}
int find(int a)
{
return (f[a]==a) ? a : f[a] = find(f[a]);
}
void merge(int a,int b)
{
int fa = find(a);
int fb = find(b);
if(fa!=fb) f[fa] = fb;
}
bool judge(int a , int b)
{
return find(a)==find(b);
}
int main(void)
{
cin>>n>>m;
init();
for(int i =0;i<m;i++)
{
cin >> z >> x >> y;
if(z==1)
{
merge(x,y);
}
else
{
if(judge(x,y)) cout << "Y" << endl;
else cout << "N" << endl;
}
}
return 0;
}
//请勿抄袭,锁号不负责!
下一次讲 什么是 加权并查集.
written by nil_the_Hedgehog 紫色刺猬🦔 (Tonyl1n)