并查集,在一些有(N)个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。
程序实现:
-
首先定义:当节点(x)与节点(y)有公共祖先时,(x,y)在同一集合中。初始状态下,每个节点应当独立。
-
则合并集合即将两棵树根节点以某种方式连接合并为一棵树。查找(x,y)在同一集合即寻找它们是否有公共祖先。
1.初始化
建立一个 parent 数组,存储每个节点的父节点,将 parent 数组初始化为-1,即每个节点互相独立。
2. 寻找节点根的函数 ( find_root ):
作用:寻找一个节点的根节点。
实现:
(1). 传入一个节点编号 x ,判断其 parent 数组值是否为-1(即是否为根节点)。
(2). 若是,则 将所有经过的节点父节点设为当前的 x 后(路径压缩) 返回当前的 x。
(3). 若不是,将x赋值为 parent[x] ,重复(1)步骤。
3. 联合函数(union):
作用:合并两个点所在集合,成功则返回(true),失败返回(false)
实现:
(1). 传入两个节点编号 x , y 找到 x , y 的根。
(2). 若 x 根与 y 根相等,返回(false)
(3). 若不等,则判断x所在树与y所在树的深度。
相等则任意以一方的根节点为根节点进行连接,被连接的一方深度+1。
不等则连接深度大的一方。
返回(true)。
(判断深度操作目的是尽量减少树的深度,从而减少寻找根的用时到(O(logn)),减小时间复杂度。否则最坏情况将有(O(n))的查找根时间)(按秩优化)
4. 查找函数(search)
作用:寻找两个节点是否在同一集合。
实现:
传入两个节点编号,返回节点根节点是否相等
完整代码
懒得切输入法所以写的英文注释
#include <bits/stdc++.h>
using namespace std;
const int VER=1000010;/*number of vertex(node)*/
int parent[VER];/*the parent of each node,initalized with -1*/
int rank_[VER];/*the depth of tree*/
int n,m;
queue<int> ans;
inline void init()
{
for(int i=0;i<VER;i++)
{
parent[i]=-1;
rank_[i]=0;
}
}
/*initalizing function*/
inline int find_root(int x)
{
int x_root=x;
while(parent[x_root]!=-1)
{
x_root=parent[x_root];
}
while(x!=x_root)
{
int tmp=parent[x];
parent[x]=x_root;
x=tmp;
}
return x_root;
}
/*This function is to find the root of node x*/
int union_(int x,int y)//return 1--success ; return 0--faild
{
int x_root=find_root(x);
int y_root=find_root(y);
if(x_root==y_root) return 0;
else
{
if(rank_[x_root]>rank_[y_root])
{
parent[y_root]=x_root;
}
else if(rank_[x_root]<rank_[y_root])
{
parent[x_root]=y_root;
}
else /*if the rank x is equal to rank y*/
{
parent[x_root]=y_root;
rank_[y_root]++;
}
return 1;
}
}
/*union the set of x and the set of y*/
inline int search_(int x,int y)
{
if(find_root(x)==find_root(y))
return 1;
return 0;
}
/*finding if x is connected with y*/
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
init();
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>z>>x>>y;
if(z==1)
union_(x,y);
if(z==2)
{
ans.push(search_(x,y));
}
}
while(!ans.empty())
{
int x=ans.front();
ans.pop();
if(x==1) cout<<"Y
";
else cout<<"N
";
}
return 0;
}