并查集(小米16年笔试题朋友圈问题)

我们先来看一道16年小米校招笔试题

假如已知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个朋友圈。

方法一:解决这个问题,我们一开始会想到set。
set1={1,2},set2={2,3},set3={4,5};
set1={1,2,3},set2={};
set3={4,5};

如果两个set集合中存在相同元素,就将元素全部放在第一个集合set1中(不会出现重复元素),第二个集合清空,继续这个过程。最后各个独立的集合不存在任何一个相同元素。然后统计不为空的集合的个数,即朋友圈的个数。

方法二:
利用位图实现:
这里写图片描述
方法三:
并查集实现
这里写图片描述

并查集定义:
实际上是一个数组,只是这个数组比较特殊,最开始将数组的每个数据看成一个单独的集合,用-1表示。然后根据要求合并,1作为组长,2,3都为组员,组长的元素为负,表示组员的个数(包括组长),即这个集合的元素总个数。最后找到该数组中负数的个数就是集合的个数,该题就得到解决了。

实现代码:

#pragma once
#include <iostream>
using namespace std;
#include <cstring>
class UnionFindSet{
public:
     //无参构造函数
     UnionFindSet()
          :array(NULL)
          , _size(0)
     {}
     //有参构造函数
     UnionFindSet(int size)
          :array(new int[size])
          , _size(size + 1)
     {
          memset(array, -1, sizeof(size_t)*size);
     }
     //查找组长元素
     int FindRoot(int child)
     {
          if (array[child] > 0)
          {
              return array[child];
          }
          else
          {
              return child;
          }
     }
     //合并两个集合
     void Union(int child1, int child2)
     {
          int root1 = FindRoot(child1);
          int root2 = FindRoot(child2);
          if (root1 != root2)
          {
              array[root1] += array[root2];//在root1的元素中加上root2中的元素个数为合并后集合元素总个数
              array[root2] = root1;//将组长元素更改为root11
          }
     }
     //集合个数
     int Count()
     {
          int count = 0;
          for (int i = 0; i < _size - 1; ++i)
          {
              if (array[i] < 0)
                   ++count;
          }
          return count;
     }
     //某个集合中的元素个数
     int Size(int child)
     {
          int root = FindRoot(child);
          return -array[root];
     }
private:
     int* array;
     size_t _size;
};
//朋友圈
void test()
{
     UnionFindSet friends(5);
     friends.Union(1, 2);
     friends.Union(2, 3);
     friends.Union(4, 5);
     int friendsCount = friends.Count();
     cout << "共有" << friendsCount << "个朋友圈" << endl;
     int tmp = friends.Size(3);
     cout << "3所在的集合有" << tmp << "个元素" << endl;
}

输出结果:
这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值