并查集算法

并查集是一类算法的总称,也可以说是一种数据结构。它其实是由三个部分组成的:

  1. 并:合并两点所在的集合
  2. 查:查询某点所在的集合
  3. 集:集合

这三种操作是并查集最重要的部分。

其实并查集本质上是一个树林,也就相当于说它的每一个集合都是一颗树。

怎么存呢?

我们用一个数组fa[i]来表示节点i的父亲.

如果i节点没有父亲,fa[i] = i.


接下来我就开始讲讲如何实现了。

三种操作中最基本的就是查询了。

其想法是从该点出发进行递归,

每一次先判断fa[i]是否等于i

如果等于i就return i,

不等于的话就问i的father

直接上代码(C++)

int get(int x) {
    if (x == fa[x]) return x;
    return get(fa[x]);
}

虽然听起来起来很高大上,但是代码就4行,想记不下来都难 ^_^

时间复杂度: O(1)~O(n) (n是该树的大小)

注:get(i) 返回的是i的根结点,根结点就代表整棵树


然后便是合并

合并是基于查询的,

其实就是先把两个点的根结点get出来

然后先康一下俩节点是不是在一个集合里,

不是的话就把任意一个节点的father设为另一个节点

代码来喽:

void merge(int x, int y) {
    x = get(x);
    y = get(y);
    if (x != y) fa[y] = x;
}

合并的代码也不算多,5行,对于你们这些大佬肯定是小case的。

时间复杂度: O(1)~O(n) (n是该树的大小)


划重点!

并查集有两种优化方法,且互不干扰

如果两种都用上可以把两个操作的时间复杂度压到O(1)!


No.1 路径压缩

路径压缩原理很简单,就是如果你查询的一个节点x,查到了根节点后把x的father设为x的根节点,

独自使用的话可以把时间复杂度压到O(logn)(n为树的大小)

只要把get改一改就行啦。

代码:

int get(int x) {
    if (x == fa[x]) return x;
    fa[x] = get(fa[x]);
    return fa[x];
}

路径压缩是并查集最常用,也是最简单的优化方式。


No.2 按秩合并

顾名思义,按秩合并就是按照秩序合并。

具体怎么按照秩序

其实就是在合并时判断一下,把深度较小的树合并到深度较大的树中去 

上代码!

int dep[maxn]; // 储存深度
void merge(int x, int y) {
    x = get(x);
    y = get(y);
    int fx = dep[x]; // 表示x树的大小
    int fy = dep[y]; // 表示y树的大小
    if (fx < fy) {
        fa[x] = y;
    } else if (fx == fy) {
        fa[x] = y;
        dep[y]++;
    else {
        fa[y] = x;
    }
}

忘记说了

初始化时要记得把fa[i]设成i, dep[i]设成1哦!

最后发下全部代码

int fa[maxn];

​int dep[maxn]; // 储存深度

int get(int x) {
    if (x == fa[x]) return x;
    fa[x] = get(fa[x]);
    return fa[x];
}

void merge(int x, int y) {
    x = get(x);
    y = get(y);
    int fx = dep[x]; // 表示x树的大小
    int fy = dep[y]; // 表示y树的大小
    if (fx < fy) {
        fa[x] = y;
    } else if (fx == fy) {
        fa[x] = y;
        dep[y]++;
    else {
        fa[y] = x;
    }
}

总结:

并查集是一个在竞赛与程序中都很常见的算法,大家一定要牢牢掌握它哦。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值