并查集:
并查集算法在天梯赛和pat甲级里属于必须掌握的算法之一。
原理及适用范围:
给定一组数据及他们之间的关系,问任意两个元素是否在一个集合内。(例如,给定一个家谱,问某两个人是否是亲戚)
很容易想到的是暴力搜索,但随着数据量的增加这种查找显然会超时。
而并查集的原理则是在每一个集合中确定一个代表元,判断两个元素是否是一个集合只需要查看对应的代表元是否在相同。这将只需要O(1)时间即可完成查询。并查集其实是森林。
并不关心一个集合内的两个元素具体是怎样的联系
并查集的代码实现:
一般来说并查集需要三个操作,初始化,查询,合并。数据结构可采用多个数组或结构体。本文采用数组讲解。
初始化:
parent[]数组:
parent[i]=a; 表示i的父亲是a。初始化所有的数据自己是自己的父亲。
[cpp] view plain copy
- for(int i=1;i<=n;i++)
- parent[i]=i;
合并:
将两个元素放在一个集合(一棵树上)
void unio(int a,int b) { int ra=find(a);//查询a元素所在集合的代表元(即它的祖先)。 int rb=find(b); if(ra!=rb) parent[rb]=ra;//两个元素如果代表元不同,则把其中一个作为另一个的代表元。由此形成一棵树的形式。 }
查询:
如何判断两个元素是否属于一个集合呢。该函数返回他们的代表元。
[cpp] view plain copy
- int find(int x)
- {
- int root=x;
- while(parent[root]!=root)
- root=parent[root];
- while(parent[x]!=root){
- int t=parent[x];
- parent[x]=root;
- x=t;
- }//循环的目的是路径压缩,是O(1)完成查询的关键,为了防止树的退化。把该元素及它所有的祖先的 父亲 全部设置为代表元.
- return root;
- }