并查集

Posted xdblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并查集相关的知识,希望对你有一定的参考价值。

主要内容

本文主要记录并查集的基本实现方法,并逐步将一些例题填充到文章中。

并查集能做什么

并查集可以:
1. 合并集合
2. 查找两个元素是否在同一个集合内
3. 集合数量
4. 确定元素属于哪个集合

完整代码示例

class UF
{
public:
    UF();
    UF(int N);
    ~UF();
    bool isConnected(int p, int q);
    int findRoot(int p);//查找根节点 主要函数
    void  unionSet(int p, int q);//合并集合 主要函数
    int getSetCount();
    int getElemCount();
    
private:
    std::vector<int> m_parent;
    std::vector<int> m_rank;
    int m_setCount; //集合个数
    int m_elemCount; //元素个数
};

UF::UF()
{
    m_setCount = 0;
    m_elemCount = 0;
}
UF::UF(int N):
    m_setCount(N), 
    m_elemCount(N)
{
    m_parent.resize(N);
    m_rank.resize(N);
    for(int i = 0; i < N; ++i)
    {
        m_parent[i] = i;
        m_rank[i] = 1;
    }
}
UF::~UF()
{
    
}


int UF::findRoot( int p )
{
    if(p != m_parent[p])
    {
        m_parent[p] = findRoot(m_parent[p]);
    }
    return m_parent[p];
}

void UF::unionSet(int p, int q )
{
    int rootOfP = findRoot(p);
    int rootOfQ = findRoot(q);
    if( rootOfP == rootOfQ ) 
        return ;
        
    if(m_rank[rootOfP] > m_rank[rootOfQ])
    {
        m_parent[rootOfQ] = rootOfP;
    }
    else
    {
        if(m_rank[rootOfP] == m_rank[rootOfQ])
        {
            m_rank[rootOfQ]++;
        }
        m_parent[rootOfP] = rootOfQ; 
    }
    m_setCount--;
}

bool UF::isConnected( int p, int q)
{
    return findRoot(p) == findRoot(q);
}

例题

LeetCode 547 朋友圈

班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。

给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。

示例 1:

输入:
[[1,1,0],
[1,1,0],
[0,0,1]]
输出: 2
说明:已知学生0和学生1互为朋友,他们在一个朋友圈。
第2个学生自己在一个朋友圈。所以返回2。

示例 2:

输入:
[[1,1,0],
[1,1,1],
[0,1,1]]
输出: 1
说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。

注意

N 在[1,200]的范围内。
对于所有学生,有M[i][i] = 1。
如果有M[i][j] = 1,则有M[j][i] = 1。

class Solution {
public:
    int findCircleNum(vector<vector<int>>& M) {
        N = M.size();
        count = N;
        parent.resize(count);
        rank.resize(count);
        for(int i = 0; i < N; i++)
        {
            parent[i] = i;
            rank[i] = 1;
        }
        for(int i = 0; i < N -1 ; ++i)
        {
            for(int j = i + 1; j < N; ++j)
            {
                if(M[i][j] == 1)
                {
                    uni(i,j);
                }
            }
                
        }
        
        return count;
        
    }
    int root(int p)
    {
        if(p != parent[p])
        {
            parent[p] = root(parent[p]);
        }
        return parent[p];
    }
    void uni(int p, int q)
    {
        int proot = root(p);
        int qroot = root(q);
        if(proot == qroot) return ;
        
        if(rank[proot] > rank[qroot])
        {
            parent[qroot] = proot;
        }
        else
        {
            if(rank[proot] == rank[qroot])
            {
                rank[qroot]++;
            }
            parent[proot] = qroot;
        }
        count--;
        
    }
    
    
    
    int N;
    vector<int> parent;
    vector<int> rank;
    int count;
};

















以上是关于并查集的主要内容,如果未能解决你的问题,请参考以下文章

想要学会并查集吗?看我四十行代码实现它

树--12---并查集

笔记并查集---无向图处理代码模板及类型题

并查集

力扣 每日一题 886. 可能的二分法难度:中等,rating: 1794(并查集 / 拆点优化的扩展域并查集)

并查集