- 💂 个人主页:努力学习的少年
- 🤟 版权: 本文由【努力学习的少年】原创、在CSDN首发、需要转载请联系博主
- 💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦
1. 并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。
2. 并查集通常包含两种操作

当有些集合 合并之后,数组会出现如下这种情况:

如:元素1的值是-4,则说明元素1是某个集合的根节点,且该集合的元素个数是4.
如:元 素2的值是1,则说明它的父亲节点的编号是元素1.
并查集的查找是判断两个元素是否在同一个集合上。

例:怎样判断元素2和元素6元素是否在同一个集合上?
判断元素2和元素6的是否在同一个集合上,我们只需要判断元素2对应的集合的根节点与元素5对应集合的根节点是否相同,因为一个集合只有一个根节点,可见元素2对应的集合的根节点是元素1
元素6的根节点的对应的集合的根节点是元素4,因此它们不在同一个集合上。
判断两个元素是否在同一个集合只需要找到他们相对应的根节点,那么如何找到一个元素对应集合的根节点?
在一个集合当中,只有根节点它的值是负数,其余的元素都是正数,因此,给我们一个元素,我们需要判断对应的值是否为负数,如果不是,在通过元素的值,找到它的父亲节点的元素,再判断父亲节点是否负数,如此循环,直到找到一个元素,它的值为负数,则为该集合的根节点。
以元素6查找集合的根节点为例:

Find的实现:
- bool Find(const int x, const int y) {
- int root_x = x, root_y = y;
- while (v[root_x] >= 0) {
- root_x = v[root_x];
- }
-
- while (v[root_y] >= 0) {
- root_y = v[root_y];
- }
-
- return root_x == root_y;
- }
并查集的合并是将一个集合合并到另一个集合上,并为一个更大的集合。
如果有两个元素,它们之间有交集,此时我们想要将这两个元素的对应的集合合并为一个集合,那么该如何合并呢?
如下:元素8和元素6它们之间存在交集,此时我们想要将8元素对应的集合与6元素对应的集合合并成一个集合,如何合并?

合并操作:

代码实现:
- bool Union(const int x, const int y) {
- int root_x = x, root_y = y;
- while (v[root_x] >= 0) {
- root_x = v[root_x];
- }
- //此时root_x为负数,则为x相对应集合的根节点
- while (v[root_y] >= 0) {
- root_y = v[root_y];
- }
- //此时root_y为负数,则为y相对应集合的根节点
- if (root_x == root_y) {
- //两个元素是在同一个集合上
- //合并失败
- return false;
- }
-
- v[root_x] += v[root_y];
- v[root_y] = root_x;
- return true;
- }
并查集整体代码
- class unionfind1 {
- public:
- unionfind1(int* x, size_t n) {
- for (int i = 0; i < n; i++) {
- v.push_back(-1);
- }
- }
-
- bool Find(const int x, const int y) {
- int root_x = x, root_y = y;
- while (v[root_x] >= 0) {
- root_x = v[root_x];
- }
-
- while (v[root_y] >= 0) {
- root_y = v[root_y];
- }
-
- return root_x == root_y;
- }
-
- bool Union(const int x, const int y) {
- int root_x = x, root_y = y;
- while (v[root_x] >= 0) {
- root_x = v[root_x];
- }
- //此时root_x为负数,则为x相对应集合的根节点
- while (v[root_y] >= 0) {
- root_y = v[root_y];
- }
- //此时root_y为负数,则为y相对应集合的根节点
- if (root_x == root_y) {
- //两个元素是在同一个集合上
- //合并失败
- return false;
- }
-
- v[root_x] += v[root_y];
- v[root_y] = root_x;
- return true;
- }
-
- private:
- vector<int> v;
- };
-
如果并查集中的元素不是一个正数,可能是一个字符串,那么上面的并查集是不能帮我们实现的。
所以我们需要加一层哈希表将 字符串 与 数组 下标映射在一起,当判断两个元素是否在同一个集合中或者合并两个元素相对应的集合,需要先通过哈希表将 字符串 转换为 数组 下标。

- template<class T>
- class unionfind {
- public:
- unionfind(T* x,size_t n) {
- for (int i = 0; i < n; i++) {
- v.push_back(-1);
- //将T类型与数组下标映射在一起
- mp.insert(pair
size_t>(x[i], i)); - }
- }
-
- bool Find(const T x, const T y) {
- //通过x,y找到相对应的数组下标
- size_t index_x = mp[x];
- size_t index_y = mp[y];
- while (v[index_x] >= 0) {
- index_x = v[index_x];
- }
-
- while (v[index_y] >= 0) {
- index_y = v[index_y];
- }
-
- return index_x == index_y;
- }
-
- bool Union(const T x, const T y) {
- //通过x,y找到相对应的数组下标
- size_t index_x = mp[x];
- size_t index_y = mp[y];
-
- while (v[index_x] >= 0) {
- index_x = v[index_x];
- }
-
- while (v[index_y] >= 0) {
- index_y = v[index_y];
- }
-
- if (index_x == index_y) {
- //两个元素是在同一个集合上
- //合并失败
- return false;
- }
-
- v[index_x] += v[index_y];
- v[index_y] = index_x;
- return true;
- }
-
- private:
- vector<int> v;
- unordered_map
int> mp; - };