zoukankan      html  css  js  c++  java
  • 并查集(Union Find)

    特点

    常用于确定无向图的连通分量(虽然DFS也可以做),求最小公共祖先(LCA)

    朴素版并查集

        vector<int> v;
        void Union(int i, int j){
            int pi = Find(i);
            int pj = Find(j);
            
            v[pi] = pj;
        }
        
        int Find(int i){
            
            while(v[i] != i) i = v[i];
            
            return i;
        }
    

    路径压缩

    为了减少树的高度,直接将查找路径上的结点连接到根上去,降低查找时间

        int Find(int i){
            if(v[i] != i) v[i] = Find(v[i]);
            return v[i];
        }
    

    按秩合并

    秩表示结点高度的上界,(算法导论上说路径压缩不会改变每个结点的秩?没想通,难道是指的上界),将秩小的树指向秩大的树称为按秩合并

        void Union(int i, int j){
            int ri = Find(i);
            int rj = Find(j);
            if(ri == rj) return ;
    
            if(Rank[ri] > Rank[rj]){
                v[rj] = ri;
            } else if(Rank[ri] < Rank[rj]){
                v[ri] = rj;
            } else {
                Rank[ri] += 1;
                v[rj] = ri;
            }
        }
    

    时间复杂度

    朴素版并查集的Union操作的摊还时间为(O(n))
    使用按秩合并的Union操作的摊还时间为(O(log_2 n))
    同时采用按秩合并和路径压缩的最坏运行时间每个操作的摊还时间为(alpha(n))(反阿克曼函数,近似为一个常数)
    详细分析可以写一本书...

    例题

    547. Friend Circles

    class Solution {
    private:
        vector<int> Rank;
        vector<int> v;
    
         void Union(int i, int j){
            int ri = Find(i);
            int rj = Find(j);
            if(ri == rj) return ;
    
            if(Rank[ri] > Rank[rj]){
                v[rj] = ri;
            } else if(Rank[ri] < Rank[rj]){
                v[ri] = rj;
            } else {
                Rank[ri] += 1;
                v[rj] = ri;
            }
        }
        
        int Find(int i){
            if(v[i] != i) v[i] = Find(v[i]);
            return v[i];
        }
        
    public:
        int findCircleNum(vector<vector<int>>& M) {
            int n = M.size();
            for(int i = 0; i < n; i++){
                v.push_back(i);
                Rank.push_back(0);
            }
            
            for(int i = 0; i < n; i++){
                for(int j = i + 1; j < n; j++){
                    if(M[i][j] == 1){
                        Union(i, j);
                    }
                }
            }
            
            
            int cnt = 0;
            
            for(int i = 0; i < n; i++){
                if(Find(i) == i) cnt++;
            }
            
            return cnt;
        }
    };
    
  • 相关阅读:
    第十六天-面向对象02-成员
    第十五天-面向对象01
    第十四天-内置函数
    第十三天-生成器
    第十二天-函数名 迭代器
    第十一天-函数进阶
    第十天-初识函数
    第九天- 文件操作 r w a 文件复制/修改
    objectives-c基本语法。
    今天开始了objective-c的学习!
  • 原文地址:https://www.cnblogs.com/qbits/p/10974667.html
Copyright © 2011-2022 走看看