【C/C++】并查集

并查集操作的简单实现

  • 原理:定义一个数组s[i]来表示第i个元素属于哪个集团,因此初始化时s[i] = i;即每个元素都还是分散的。对于可以合并的两个元素x与y,查找到他们两个所属的集团,将其中一个合并到另一个即可;
  • 代码实现:
#include<bits/stdc++.h>

using namespace std;

const int maxn = 1e4 + 10;
int s[maxn];

void init_set(int n)
{
    for(int i=1; i<=n; i++)
        s[i] = i;
}

int find_set(int x)//查询x的集团编号
{
    return s[x] == x?x:find_set(s[x]);
}

void union_set(int x, int y)
{
    x = find_set(x);
    y = find_set(y);
    if(x != y) s[x] = s[y];
}

int main()
{
    int n,m,x,y;
    while(~scanf("%d %d",&n,&m))
    {
        init_set(n);//初始化
        for(int i=0; i<m; i++)
        {
            scanf("%d %d",&x,&y);
            union_set(x, y);//将x的集团与y的集团合并
        }
        int ans = 0;
        for(int i=1; i<=n; i++)//统计有多少个集团
            if(s[i] == i)
                ans++;
        printf("%d\n",ans);
    }
    return 0;
}

合并的优化

  • 将两个集团合并时,可以看做是两个树的合并,而高度较小的树合并到较大的树上可以使树的高度不变。引入一个数组height[i]来表示树的高度即可
  • 代码实现:

void init_set(int n)
{
    for(int i=1; i<=n; i++)
    {
        s[i] = i;
        height[i] = 0;
    }
}

void union_set(int x, int y)
{
    x = Find_set(x);
    y = Find_set(y);
    if(height[x] == height[y])
    {
        height[x]++;
        s[y] = x;
    }
    else
    {
        if(height[x] > height[y]) 
            s[y] = x;
        else 
            s[x] = y;
    }
}

查询的优化

  • 每次搜索的过程中,如果顺便将i所属的集团改为根节点,再次查找i的时候就可以直接返回结果了
  • 代码实现
//递归查询,容易爆栈
int find_set(int x)
{
    if(x != s[x]) 
        s[x] = find_set(s[x]);
    return s[x];
}

//非递归查询
int Find_set(int x)
{
    int r = x;
    while(r != s[r]) r = s[r];
    int i=x,j;
    while(i != r)
    {
        j = s[i];
        s[i] = r;
        i = j;
    }
    return r;
}

原文链接: https://www.cnblogs.com/spirit-blog/p/12380379.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    【C/C++】并查集

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/332365

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月1日 下午6:27
下一篇 2023年3月1日 下午6:28

相关推荐