二叉树的并查集

并查集是一种用于处理不相交集合合并问题的树形数据结构。查找操作通过沿着parent数组找到集合的根结点,合并操作则通过调整parent数组避免树的退化,保持平衡。文章提供了查找和合并函数的实现,并给出了一组样例输入和输出,展示了如何使用并查集解决实际问题。

1.定义

一种树形的数据结构,用于处理一些不想交集合的合并问题。

2.查找

(1)初始化

对于查找操作,假设需要确定x所在的集合,也就是确定集合的父结点。可以沿着parent [ x ]不断在树形结构上移动,直到到达根结点。对于每一个元素parent [ x ] 指向x在树形结构上的父节点。如果x是根结点,则令parent [ x ]=x;

#define max 1e+10

int parent[max]; //也可以是是parent[max]
int rank[max]; //深度(层次),通常初始化为0*可要可不要*

for(int i=0;i<n;i++)
{
    parent[i]=i;
    rank[i]=0;
}

 

(2)查找函数

如果的 序列的parent等于他的下标,那么自然返回自身编号;如果不同(即经过了合并操作后指针指向了源头),那么就可以调用递归函数。

int find(int num)
{
    if(parent[num]==num)  //如果它是属于这个父结点下面的就返回这个数的下标,否则继续寻找
      return parent[num];  
     return find(parent[num]);
}

 (3)合并函数

假设需要合并两个数组元素分别为 x 和 y ,则只需要令parent [ x ]=y, 或者parent [ y ]= x; 为了使合并后的树不产生退化,即使树中左右子树的深度差尽可能小,对于每一个元素 x ,维护rank[x]为以 x 为根的子树的深度,合并时 若 rank[x]< rank[y],则令 parent[x]=y;否则parent[y]=x;

 

void union(int x,int y)
{
   int i=find(x);
   int j=find(y);
    if(i==j)
      return ;
if(rank[i]>rank[j])  
   parent[j]=i;
else
  {
      if(rank[i]==rank[j])  
        rank[j]++;
        parent[i]=j;          
  }
}

统计最后有多少个不相交的集合

int count=0;

//即计算有多少个parent[num]=num;

【模板】并查集


题目描述

如题,现在有一个并查集,你需要完成合并和查询操作。

输入格式

第一行包含两个整数 N,M ,表示共有 N 个元素和 M个操作。

接下来 M 行,每行包含三个整数 Zi, Xi, Yi 。

当 Zi=1 时,将 Xi 与 Yi 所在的集合合并。

当 Zi=2 时,输出 Xi 与 Yi 是否在同一集合内,是的输出Y ;否则输出 N 。

输出格式

对于每一个 Zi=2 的操作,都有一行输出,每行包含一个大写字母,为 Y 或者 N 。

样例输入 #1

4 7

2 1 2

1 1 2

2 1 2

1 3 4

2 1 4

1 2 3

2 1 4

样例输出 #1

N

Y

N

Y

 

提示

对于 30% 的数据,N<= 10,M<= 20。

对于 70% 的数据,N<=100,M<=10^3。

对于 100% 的数据,1<=N <=10^4,

1<=M<=2*10^5,1<= Xi, Yi<=N,Zi ∈ { 1, 2 }。

#include<stdio.h>
int tree[100000];
int n,m,x,y,z;
int fun(int num)
{
    if(tree[num]==num)
        return num;
    return tree[num]=fun(tree[num]);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
        tree[i]=i; //初始化
    for(int i=0; i<m; i++)
    {
        scanf("%d%d%d",&z,&x,&y);
        if(z==1)
            tree[fun(x)]=fun(y);  //合并
        else
        {
            if(fun(x)==fun(y))     //查找
                printf("Y\n");
            else printf("N\n");
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值