所谓并查集,就是将N个不同的元素分成一组不相交的集合
在数据结构中有一种很典型的朋友圈问题,假设有10个人,分别为0到9号,若1和2是朋友,2和3是朋友,3和4是朋友,则成这4个人为一个朋友圈,又有5和6是朋友,7和8是朋友,7和9是朋友,0没有朋友,问这个9个人中有多少朋友圈,这时虽然方法也有,但相对于我们介绍的这种结构,其他的开销就太大了。
结构:
开始时,每个元素就是一个集合,并且初始化为-1,然后按规律将将个集合进行合并。
当两个集合合并时,如(1,2)合并,把1作为根,将2所在位置的数值加到1所在位置上,并将2位置数值改为他的根(即1);反过来也可以。
这样操作完成之后,下标为负数的一定为根,且其数值的绝对值为集合中的元素个数,下标为非负数的则是他的根。我们只需要查找有几个负数节点就可以知道有几个集合了;
将我们的例题进行合并后:
代码如下:
class UnionFindSet//并查集
{
public:
UnionFindSet(size_t n)
{
_set.resize(n, -1);
}
int FindRoot(int x)
{
while (_set[x] >= 0)
x = _set[x];
return x;
}
void Union(int x1, int x2)
{
int root1 = FindRoot(x1);
int root2 = FindRoot(x2);
if (root1 != root2)
{
_set[root1] += _set[root2];
_set[root2] = root1;
}
}
bool IsIn(int x1, int x2)
{
int root1 = FindRoot(x1);
int root2 = FindRoot(x2);
if (root1 == root2)
return true;
return false;
}
protected:
vector<int> _set;
};