假如已知有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属于另一个朋友圈,结果为两个朋友圈
在处理这道题的时候,我用的是并查集来处理的
什么是并查集:
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。在一些有N个元素的集合应用问题中,通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中
下面来看看关键代码的实现以及图解
<strong><span style="font-size:18px;"> int FindRoot(int x)
{
if (_set[x] >= 0)
{
x = _set[x];
}
return x;
}</span></strong>
<strong><span style="font-size:18px;"> void Union(int x1,int x2)
{
int root1 = FindRoot(x1);
int root2 = FindRoot(x2);
if (root1 != root2)
{
_set[root1] += _set[root2];
_set[root2] = root1;
}
}</span></strong>
下面是全部代码及其测试
“test.cpp”
<strong><span style="font-size:18px;">#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#include <assert.h>
class UnionFindSet
{
public:
//构造函数
UnionFindSet(int n)
:_n(n)
,_set(new int[n])
{
//初始化_set数组,全部初始化为-1
memset(_set,-1,sizeof(int)*n);
}
void Union(int x1,int x2)
{
int root1 = FindRoot(x1);
int root2 = FindRoot(x2);
if (root1 != root2)
{
_set[root1] += _set[root2];
_set[root2] = root1;
}
}
int Count()
{
int count = 0;
for (size_t i = 0;i < _n;i++)
{
if (_set[i] < 0)
{
count++;
}
}
return count-1;//0的位置一开始就初始化成-1,0的位置不用
//故_set[0]为负数不属于一个朋友圈
}
private:
int FindRoot(int x)
{
if (_set[x] >= 0)
{
x = _set[x];
}
return x;
}
protected:
int* _set;//设置一个数组存放值
int _n;
};
int Friend(int n,int m,int r[][2])
{
assert(r);
UnionFindSet ufs(n+1);//0的位置不用
for (size_t i = 0;i < m;i++)
{
int r1 = r[i][0];
int r2 = r[i][1];
ufs.Union(r1,r2);
}
return ufs.Count();
}
void Test1()
{
int r[3][2] = {{1,2},{2,3},{4,5}};//n=总人数,m=多少对好友关系
cout<<"朋友圈?"<<Friend(5,3,r)<<endl;
}
void Test2()
{
int r[][2] = {{1,2},{2,3},{4,5},{5,9},{6,2},{7,8}};//n=总人数,m=多少对好友关系
cout<<"朋友圈?"<<Friend(9,6,r)<<endl;
}
int main()
{
Test1();
//Test2();
system("pause");
return 0;
}</span></strong>