并查集:把具有相同属性的对象集中在一起(连在同一个树根上),构成了一个集合。
并查集的作用:查找两个对象是否属于同一个集合(是否连在同一个树根上),和有几个集合。
并查集的操作:1. 某个对象存在那个集合里(连在哪个树根上)。
2.集合的合并。
3.此时的并查集树有几个集合(树根)。
要找一个对象存在的集合,要先构造一个find()函数。去找树根。
int findfather(int v)
{
if(v == a[v]) return v ;
return findfather(a[v]);
}
非递归操作:
int findfather(int v)
{
int i , j , k ;
i = v ;
while(i != a[i])
{
i = a[i] ;
}
k = v ;
while(k != i) //路径压缩。让子节点的usize[]为0;
{
j = a[k] ;
a[k] = i ;
k = j ;
}
return i ;
}
集合的合并:usize[]是记录每个结点下面的子节点个数。初始化为0.
void unionroot(int x , int y)
{
int fx = findfather(x) ;
int fy = findfather(y) ;
if(uszie[fx] > usize[fy])
a[fy] = fx ;
else if(usize[fx] < usize[fy])
a[fx] = fy ;
else
{
a[fx] = fy ;
usize[fy] ++ ;
}
}
举个例子吧:
A={1 , 2,3,4} , B={5,6,7} ,C={8,9}。
把这个并查集表是出来。
代码:
#include <iostream>
using namespace std;
int a[10] ;
int usize[10] ;
int findfather(int v)
{
if(v == a[v]) return v ;
return findfather(a[v]);
}
void unionroot(int x , int y)
{
int fx = findfather(x) ;
int fy = findfather(y) ;
if(usize[fx] > usize[fy])
a[fy] = fx ;
else if(usize[fx] < usize[fy])
a[fx] = fy ;
else
{
a[fx] = fy ;
usize[fy] ++ ;
}
}
void init()
{
for(int i = 1; i < 10; i ++)
{
usize[i] = 0 ;
a[i] = i ;
}
}
int main()
{
init() ;
int x , y ;
for(int i = 0; i < 6; i ++)
{
cin >> x >> y ;
unionroot(x , y) ;
}
return 0 ;
}
并查集的查找操作,带路径压缩。
int findfather(int x)
{
if( x == parent[x]) return x ;
return parent[x] = findfather(parent[x]);
}
为什么?
这要深人理解递归,当找到根时逐层返回根给parent[x];
要理解递归的返回过程。