并查集
一、定义
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题
集合定义方法:“代表元法”,每个集合选择一个节点作为整个集合的代表,最根部的父亲节点
二、基本操作
Find——查询一个元素属于哪一个集合
Merge——把两个集合合并成一个大集合
三、常规操作、路径压缩与按秩合并
初始化
一开始初始化将每个节点所在集合的代表节点都设为自己
for(int i=1;i<=n;i++)
{
f[i]=i;
}
Find函数
查询当前节点所在集合的代表节点(根节点)
int find(int x){
return f[x] == x ? x : find(f[x]);
}
常规合并
如果不是同一个集合,就将x整个集合插入y集合当做一个子节点
void merge (int x,int y) {
int n, m;
n = Find (parent, x);
m = Find (parent, y);
if (m != n) {
f[n] = m;
}
}
路径压缩
将访问过的节点直接指向树根,均摊复杂度
int find(int x) { return x == f[x] ? f[x] : f[x] = find(f[x]); }
按秩合并
“秩”:树的深度(未路径压缩) / 集合大小 。均摊复杂度
将”秩“记录在 “代表元素” ,合并时,将“秩”较小的树根 作为“秩”较大的树根的子节点
void unionn(int x, int y){//按大小合并
int u=Get(x), v=Get(y);
if(u != v) {
if(size[u]<size[v]) f[u]=v, size[v]+=size[u];//按大小合并每次要更新大小
else f[v]=u, size[u]+=size[v];
}
}
void unionn(int x, int y)
{//按深度合并//启发式合并
int u=Get(x), v=Get(y);
if(u != v) {
if(high[u] < high[v]) f[u] = v;
else {
f[v]=u;
if(high[u]==high[v]) high[u]++;//按深度合并只有在两树高度相等的时候更新
}
}
}
三、作用
操作1:统计当前产生的集合数目
for(int i=1;i<=n;i++)
{
if(f[i]==i)
cnt++;
}
因为初始化时f[i]=i,每个集合的树根节点会保留f[i]=i,统计集合个数其实就是在统计root个数
操作2:判断是否成环
简单说就是先把每一个顶点放在一个独立的集合(树)里,如果顶点之间是邻接的那么就把他们合并为一个集合(树)。一个集合(树)里有一个根结点,如果有两个顶点他们的根结点相同说明他们处于同一个集合(树),那这两个结点邻接必定形成一个环(为什么? 因n个顶点和n-1条边形成的连通图如果再加一条边一定出现环)。如果他们的根结点不同,就把这两个集合合成一个集合。
…有待补充