并查集简单介绍

定义

并查集(Disjoint-Set)是一种可以动态维护若干个不重叠的集合,并支持合并与查询两种操作的一种数据结构。并查集可以高效地进行如下操作。

  • 查询元素a和元素b是否属于同一组
  • 合并元素a和元素b所在的组

:::hljs-center
在这里插入图片描述
:::

并查集的结构

并查集也是使用树形结构实现的,不过不是二叉树。每个元素对应一个节点,每个组对应一棵树。在并查集中,哪个节点是哪个节点的父亲以及树的形状等信息无需多家关注,整体组成一个树形结构才是重要的。
:::hljs-center
在这里插入图片描述
:::

具体实现

我们建立一个数组或parent[]表示一个并查集,parent[i]表示i的父节点。

1. 初始化:

每一个点都是一个集合,因此自己的父节点就是自己fa[i]=i

for(int i = 1; i <= maxn; i++)
        fa[i] = i;

2. 查询

每一个节点不断寻找自己的父节点,若此时自己的父节点就是自己,那么该点为集合的根结点,返回该点。

int Find(int x){
    if(x==pre[x]) 
        return x;
    return Find(pre[x];
}

3. 合并:

合并两个集合只需要合并两个集合的根结点,即fa[RootA]=RootB,其中RootA,RootB是两个元素的根结点。

void merge(int x,int y){
    int fx=Find(x), fy=Find(y);
    if(fx!=fy) 
        pre[fx]=fy;
}

优化

并查集在合并是会出现这样的问题:
:::hljs-center
在这里插入图片描述
:::
在树形数据结构中,如果发生了退化的情况,那么复杂度就会变得很高。因此有必要避免退化。

1. 合并优化

  • 对于每棵树,记录这棵树的高度(rank)
  • 合并时如果两个数的rank不同,那么从rank小的向rank大的连边。

:::hljs-center
在这里插入图片描述
:::

2. 路径压缩

通过路径压缩,可以使得并查集更加高效。对于每个节点,一旦向上走到了一次根节点,就把这个点到父亲的边改为直接连向根。
:::hljs-center
在这里插入图片描述
:::
在此之上,不仅仅是所查询的节点,在查询过程中向上经过的所有节点,都改为直接连到根上。这样再次查询这些节点时,就可以很快知道根是谁了。
:::hljs-center
在这里插入图片描述
:::

完整实现

int parent[MAX_N];//父亲
int rank[MAX_N];//树的高度

//初始化n个元素
void init(int n){
    for(int i=0;i<n;i++){
        parent[i]=i;
        rank[i]=0;
    }
} 

//查询树的根
int find(int x){
    if(parent[x]==x)
        return x;
    else
        return parent[x]=find(parent[x]);    //实现了路径压缩
} 

//合并x和y所属的集合
void unite(int x,int y){
    x = find(x);
    y = find(y);
    if(x == y)
        return;
    if(rank[x] < rank[y])
        parent[x]=y
    else if(rank[x] == rank[y]){
        parent[x] = y;
        rank[y]++;
    }
    else
        parent[y]=x;
} 

//判断x和y是否属于同一个集合
bool same(int x,int y){
    return find(x)==find(y);
} 

参考:https://www.jianshu.com/p/89cea54d3f22

发布了157 篇原创文章 · 获赞 71 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览