并查集 UnionFindSet

岛问题

【题目】一个矩阵中只有0和1两种值,每个位置都可以和自己的上、下、左、右四个位置相连,如果有一片1连在一起,这个部分叫做一个岛,求一个矩阵中有多少个岛?

【举例】

0 0 1 0 1 0

1 1 1 0 1 0

1 0 0 1 0 0

0 0 0 0 0 0

这个矩阵中有三个岛

void infect(vector<vector<int>>& m, int i, int j, int N, int M){
    if(i < 0 || i >= N || j < 0 || j >= M || m[i][j] != 1){
        return;
    }
    m[i][j] = 2;
    infect(m, i + 1, j, N, M);
    infect(m, i - 1, j, N, M);
    infect(m, i, j + 1, N, M);
    infect(m, i, j - 1, N, M);
}

int island(vector<vector<int>>& m){
    if(m.empty() || m[0].empty()){
        return 0;
    }
    int N = m.size();
    int M = m[0].size();
    int res = 0;
    for(int i = 0; i < N; i++){
        for(int j = 0; j < M; j++){
            if(m[i][j] == 1){
                res++;
                infect(m, i, j, N, M);
            }
        }
    }
    return res;
}

并查集

接口:bool isSameSet(a, b)  void unionSet(a, b)

初始化:

unionSet(a, b)

unionSet(b, e); unionSet(c, d);

unionSet(b, d)

优化:

在查找Y的顶部时,会把查找沿途地点直接指向顶部

解决并查集中链过长的问题,使得下次操作可以一步到位

template <typename T>
class Element{
public:
    T val;
    Element(T val) : val(val) {}
};

template <typename T>
class UnionFindSet{
public:
    unordered_map<T, Element<T> *> elementMap;
    unordered_map<Element<T>*, Element<T>*> fatherMap;
    unordered_map<Element<T>*, T> sizeMap;

    UnionFindSet(vector<T>& arr){
        for(T i : arr){
            Element<T> *temp = new Element<T>(i);
            elementMap.insert(make_pair(i, temp));
            fatherMap.insert(make_pair(temp, temp));
            sizeMap.insert(make_pair(temp, 1));
        }
    }

    Element<T>* findHead(Element<T> *element){
        stack<Element<T>*> path;
        while(element != fatherMap[element]){
            path.push(element);
            element = fatherMap[element];
        }
        while(!path.empty()){
            fatherMap[path.top()] = element; path.pop();
        }
        return element;
    }

    bool isSameSet(T a, T b){
        if(elementMap.find(a) != elementMap.end() && elementMap.find(b) != elementMap.end()){
            return findHead(elementMap[a]) == findHead(elementMap[b]);
        }
        return false;
    }

    void unionSet(T a, T b){
        if(elementMap.find(a) != elementMap.end() && elementMap.find(b) != elementMap.end()){
            Element<T> *aHead = findHead(elementMap[a]);
            Element<T> *bHead = findHead(elementMap[b]);
            if(aHead != bHead){
                Element<T> *big = sizeMap[aHead] > sizeMap[bHead] ? aHead : bHead;
                Element<T> *small = big == aHead ? bHead : aHead;
                fatherMap[small] = big;
                sizeMap[big] += sizeMap[small];
                sizeMap.erase(small);
            }
        }
    }
};

如果并查集中有N个元素,findHead次数达到O(N)水平,单次findHead代价O(1)

【题目】

设计一个并行算法解决岛问题:

一个矩阵中只有0和1两种值,每个位置都可以和自己的上、下、左、右四个位置相连,如果有一片1连在一起,这个部分叫做一个岛,求一个矩阵中有多少个岛?

【举例】

0 0 1 0 1 0

1 1 1 0 1 0

1 0 0 1 0 0

0 0 0 0 0 0

这个矩阵中有三个岛

两个cpu:

左侧cpu找到两个岛A和B,右侧cpu找到两个岛C和D。

两cpu记录每个边界1点所对应的岛。

因此,在两个cpu各自找到两个岛后,走一遍边界节点,自上往下:

islandNum = 4;

unionSet(A, C); islandNum--;

unionSet(B, C); islandNum--;

unionSet(B, D); islandNum--;

unionSet(A, D); 

多个cpu:

每个cpu找自己的岛,收集自己的四个边界的信息,最后合并

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芜湖高学成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值