小米面试题——并查集(关于朋友圈问题)

来源:互联网 发布:网络变压器厂商 编辑:程序博客网 时间:2024/06/04 00:36
   假如已知有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数组,全部初始化为-1memset(_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>



0 0