目录
并查集概念
合并
查找集合的数量
并查集类代码实现
并查集概念
并查集和堆一样,都是通过数组来实现树的节点映射,不过并查集作用是,把一堆数据分为不同的几个小集合
不过并查集是森林的概念,并查集的学习可以帮助我们去更好的学习图这个数据结构
这里我们举一个例子:
假设我们有一个旅游团,一共有十个人,编号是0~9;
其中 s1 = {0,6,7,8} 这几个人来自湖北
s2 = {1,4,9} 这几个人来自四川
s3 = {2,3,4} 这几个人来自北京
上面我们把十个人分为了不同几个小组,他们来自不同的地方,吃的口味自然不同,于是就分别让0,1,2这三个人担任组长,带领各自的队伍去吃饭。
队长可以抽象的理解为头结点,组员理解为各自的孩子结点
数组的初始化规则定义如下:
1.每一个下标存放自己的双亲结点下标
2.如果该结点是双亲结点,存放一个负数,我们可以顺便存放这棵树的结点个数
特点:
- 一个位置是负数,那他就是树的根,这个绝对值就是棵树的结点个数
- 一个位置值是负数那他就是双亲的下标
合并
我们假设上面的s1和s2发生了合并,咋办呢?
步骤:
- 先找到两个需要合并集合的双亲结点
- 再把集合2的根下标存放的值+=集合1的根下标,在把集合2的根下标存放的值置为集合1的根
查找集合的数量
我们只需要将整个数组遍历一遍,找到为负数的位置有多少个,即集合的数量
并查集类代码实现
class UnionFindSet
{
public:UnionFindSet(size_t n):_ufs(n, -1){}void Union(int x1, int x2){// 1.先找根int root1 = FindRoot(x1);int root2 = FindRoot(x2);//如果在一个集合就没有必要去合并if (root1 == root2){return;}//将集合2合并到集合1_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}// 找根/双亲int FindRoot(int x){ int parent = x;while (_ufs[parent] >= 0){parent = _ufs[parent];}return parent;}bool InSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}size_t SetSize(){size_t size = 0;for (size_t i = 0; i < _ufs.size(); ++i){if (_ufs[i] < 0){++size;}}return size;}private:vector<int> _ufs;
};