数据结构--并查集

来源:互联网 发布:mac movist 破解 编辑:程序博客网 时间:2024/06/02 04:02

引:例题

小米公司一道面试题:
假如已知有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属于另一个朋友圈,共有两个朋友圈。请写出相应程序。

并查集

定义:
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。常常在使用中以森林来表示。
集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。

实现:
用小米面试题为例,我们可以用树形结构表示不同的朋友圈。
1,2,3属于一个朋友圈。
4,5属于一个朋友圈。
这里写图片描述
我们可以用一个大小的6的数组表示。

(这里如果用大小为6的数组,则最后朋友圈个数结果应减1,因为数组下标为0的多加了一次。也可以用大小为5的数组)

数组的初始值全部为-1。

(这里-1,1为此数的结点个数,负号起到一个标识区分的作用。)

当两个人为一个朋友圈时,第一个人下标所在的值为两个下标所在值的和,第二个人的值为第一个人的下标。

当1,2为一个朋友圈时:
这里写图片描述
当2,3为朋友圈时:

这时查到2下标处的值不为负数,则应该继续查找2的值所对应的下标处,直到找到跟为止。
找到此数字,再将两者相加

这里写图片描述

其余好友关系同上
最后,统计朋友圈的个数,只需要统计数组中有几个负数即可。

代码实现:

#pragma once#include <stdio.h>#include <assert.h>#include <vector>using namespace std;class Union_Find_Sets{public:    Union_Find_Sets(size_t size)    {        s.resize(size, -1);    }    int FindRoot(int x)    {        int root = x;        while (s[root] >= 0)        {            root = s[root];        }        return root;    }    void Union(int x1,int x2)    {        //先找X1与X2的根        int root1 = FindRoot(x1);        int root2 = FindRoot(x2);        //如果两个元素在同一集合中 则相加会出错        if (root1 != root2)        {            s[root1] += s[root2];            s[root2] = root1;        }    }    //看两个结点是否属于同一集合 只需要看两个跟是否相同    bool IsSameSet(int x1,int x2)    {        return FindRoot(x1) == FindRoot(x2);    }    //看有多少集合数目 只需要看非负数的个数    size_t SetSize()    {        size_t count = 0;        for (size_t idx = 0; idx < s.size(); idx++)        {            if (s[idx] < 0)                count++;        }        return count;    }private:    vector<int> s;};void Test(){    Union_Find_Sets st(10);    st.Union(0, 3);    st.Union(6, 8);    st.Union(3, 6);    st.Union(4, 1);    st.Union(1, 5);    st.Union(2, 7);    st.Union(7, 9);    cout<<st.IsSameSet(0, 9)<<endl;    cout<<st.SetSize()<<endl;}
原创粉丝点击