在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题。有一个联合-查找算法(union-find algorithm)定义了两个用于此数据结构的操作:
- Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
- Union:将两个子集合并成同一个集合
问题:
假如已知有n个人和m对好友关系(存于数字r)。如果两个人是直接或间接的好友(好友的好友的好友…),则认为他们属于同一个朋友圈,请写程序求出这n个人里一共有多少个朋友圈。假如:n = 5,m = 3,r = {{1 , 2} , {2 , 3} , {4 , 5}},表示有5个人,1和2是好友,2和3是好友,4和5是好友,则1、2、3属于一个朋友圈,4、5属于另一个朋友圈,结果为2个朋友圈。
并查集森林是一种将每一个集合以树表示的数据结构,其中每一个节点保存着到它的父节点的引用,例如对于本题目
并查集的实现可以理解成森林。每一个下标对应是是一棵树。在这里我们用可以用一个数组来表示这个森林,而根节点的内容我们认为都是-1。所以,默认的整个数组数值都为-1。即初始化为:
具体实现过程:
实现代码:
#pragma once
#include<iostream>
#include<vector>
using namespace std;
class UnionSet {
public:
UnionSet(int n)
{
_v.resize(n + 1, -1);
}
//n个人 m对关系
int Find(int index)
{
int root = index;
while (_v[root]>=0)
{
root = _v[root];
}
return root;
}
void Merge(int n,int m, int r[][2])
{
for (int i = 0; i < m; i++)//合并两个集合
{
//找到真正的根 对根操作
int root1 = Find(r[i][0]);
int root2 = Find(r[i][1]);
if (root1 != root2)
{
//合并两个集合
_v[root1] += _v[root2];
_v[root2] = root1;
}
}
}
int CountSet()
{
int count = 0;
for (size_t i = 1; i < _v.size(); i++)
{
if (_v[i] < 0)
count++;
}
return count;
}
private:
vector<int> _v;
};
void TestUnionSet()
{
int n = 5;
int m = 3;
int r[][2] = { {2,1},{3,2},{4,5 } };
UnionSet u(n);
u.Merge(n, m, r);
int count = u.CountSet();
cout << count << endl;
int i = 0;
}