并查集实现

对于一个集合S={a1, a2, …, an-1, an},我们还可以对集合S进一步划分: S1,S2,…,Sm-1,Sm,我们希望能够快速确定S中的两两元素是否属于S的同一子集。

举个栗子,S={0,1, 2, 3, 4, 5, 6},如果我们按照一定的规则对集合S进行划分,假设划分后为S1={1, 2, 4}, S2={3, 6},S3={0, 5},任意给定两个元素,我们如何确定它们是否属于同一子集?某些合并子集后,又如何确定两两关系?基于此类问题便出现了并查集这种数据结构。
并查集有两个基本操作:

Find: 查找元素所属子集
Union:合并两个子集为一个新的集合
 

实现:

首先设置一个哈希表将每一个元素指向自己,自己做自己的父节点

再设置一个哈希表将父节点再指向这个父节点的父

最后设置一个哈希表 祖宗节点 以及有多少个元素

class Element{
    public: 
    Element(int v)
    {
        value = v;
    }

    int operator!=(Element b)
    {
        return this->value != b.value;
    }

    int operator==(Element b)
    {
        return this->value == b.value;
    }

    int operator<(const Element &b) const
    {
       return this->value < b.value; //自定义类型做map的key必须重载<
    }

    public:
        int value;
};

class Solution {
public:

    map<int, Element> elementMap;
    map<Element, Element> fatherMap;
    map<Element, int> sizeMap;

    void insertMap(vector<int> nums){
        for(int i = 0; i < nums.size(); i++)
        {
            Element ele(nums[i]);
            elementMap.insert(pair<int, Element>(nums[i], ele));
            fatherMap.insert(pair<Element, Element>(ele, ele));
            sizeMap.insert(pair<Element,int>(ele,1));
        }
    }

    Element findHead(Element element)
    {
        while(element.value != fatherMap.find(element)->second.value)
        {
            element = fatherMap.find(element)->second;
        }
        return element;
    }

    int isSameSet(int a, int b)
    {
        if(elementMap.find(a)!=elementMap.end() && elementMap.find(b) != elementMap.end())
        {
            return findHead(elementMap.find(a)->second) == findHead(elementMap.find(b)->second);
        }
        return 0;
    }

    void Union(int a, int b)
    {
        if(elementMap.find(a)!=elementMap.end() && elementMap.find(b) != elementMap.end()){
            Element aF = findHead(elementMap.find(a)->second);
            Element bF = findHead(elementMap.find(b)->second);
            if(aF != bF)
            {
                Element big = sizeMap.find(aF)->second > sizeMap.find(bF)->second ? aF : bF;
                Element small = (big == aF) ? bF : aF;
                
                fatherMap.erase(small);//map重复key不能直接覆盖 会被无视掉 需要先移除再添加
                fatherMap.insert(pair<Element,Element>(small, big));

                int tempbigNum = sizeMap.find(big)->second;
                sizeMap.erase(big);
                sizeMap.insert(pair<Element,int>(big, tempbigNum + sizeMap.find(small)->second));
                sizeMap.erase(small);
            }
        }
    }
};

 优化

    Element findHead(Element element)
    {
        stack<Element> path;
        while(element.value != fatherMap.find(element)->second.value)
        {
            path.push(element);
            element = fatherMap.find(element)->second;
        }
        while(!path.empty())
        {
            fatherMap.insert(pair<Element,Element>(path.top(), element)); // 将每一个节点都直接连接到祖宗节点
            path.pop();
        }
        return element;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值