首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >客户端基本不用的算法系列:并查集算法介绍(union-find)

客户端基本不用的算法系列:并查集算法介绍(union-find)

作者头像
用户2932962
发布于 2019-08-09 08:31:20
发布于 2019-08-09 08:31:20
80900
代码可运行
举报
文章被收录于专栏:程序员维他命程序员维他命
运行总次数:0
代码可运行

并查集算法(union-find)

接受了大家的反馈,决定将之前的图论告一段落,我在基础的数据结构和数据处理的场景下找一些好玩的算法来写写。这些东西会极大的帮助你的面试,在那些需要考算法的大厂运用这些知识来解题是十分加分的。

在 LeetCode 上有一道题 LeetCode-547 朋友圈[1],题目大意是这样:

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

这题最后让我们求得集合数。其实无论在工作中还是在生活中,这种分组问题十分常见。我们当然可以把每一类东西往一个 Array 或者是 Set 中塞入,然后不断的去搜每一个集合是否有关联进而合并组,最终也可求得分组数。但是拍脑袋想,我们要遍历 N 次每个集合,真的是一个超级耗时的办法。

那么有什么更加优美的数据结构来解决这类问题呢?其实就是今天要讲的并查集(union-find)

并查集是什么?

并查集是用来管理元素分组状况的数据结构。并查集可以高效地执行如下操作。不过需要注意并查集虽然可以进行合并操作,但是无法进行分割操作。

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

并查集的结构

使用树形结构来实现,但不是二叉树。

每个元素对应一个节点,每个组对应一棵树。在并查集中,哪个节点是哪个节点的父亲以及树的形状信息无需多加关注,树形结构这个整体才是最重要的

1. 初始化

我们准备 n 个节点来表示 n 个元素,最开始没有边。

2. 合并

例如下图,从一个组的根向另一个组的根相连,这样两棵树就变成了一棵树,也就把两个组合并为一个组了。

其实我们发现合并并没有一个固定的规律,只要将两棵不规则树合起来就好。

3. 查询

为了查询两个节点是否属于同一个组,我们需要沿着树向上走,来查询包含这个元素的树的根是谁。如果两个节点走到了同一根,那么就说明它们属于同一组。

例如下图中,元素 2 和元素 5 都走到了元素 1,因此它们属于同一组。另一方面,由于元素 7 走到的是元素 6 ,因此同元素 2 或元素 5 属于不同组。

实现

好了,这种场景我们需要怎样实现呢?是否需要一个复杂的树来做呢?其实不用,请记住:虽然我们的思路是通过树型结构来解决,但是代码实现永远不要局限于思路。类似于二叉树,我们同样的也可以通过一维数组来实现,并查集也是如此。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
using namespace std;

int id[100000];
int cnt = 0;

int find(int p) {
    while (p != id[p]) {
        p = id[p];
    }
    return p;
}

void unio(int p, int q) {
    int rp = find(p);
    int rq = find(q);
    if (rp == rq) return;
    id[rp] = rq;
    cnt --;
}

int main() {
    cnt = 7;

    for (int i = 0; i < cnt; ++ i) {
        id[i] = i;
    }

    unio(0, 1);
    unio(1, 4);
    unio(5, 3);
    unio(3, 6);

    cout << cnt << endl; // 3 个集合

    cout << "0 的根" << find(0) << endl; // 0 的根4
    cout << "1 的根" << find(1) << endl; // 1 的根4
    cout << "2 的根" << find(2) << endl; // 2 的根2
    cout << "3 的根" << find(3) << endl; // 3 的根6
    cout << "4 的根" << find(4) << endl; // 4 的根4
    cout << "5 的根" << find(5) << endl; // 5 的根6
    cout << "6 的根" << find(6) << endl; // 6 的根6
    return 0;
}

这里有一张动图,大家点击原文查看一下。

复杂度

通过上图,我们不难看出,这棵数的深度可能会越来越深。在对于 find 来说,可能会带来较大的性能消耗,while 循环次数增多。此时 union 操作主要依赖于 find 操作,而 find 操作的时间复杂度取决于这棵树的深度。所以查询和合并操作都是 O(m)。

倘若我们有方法减少树的深度,是不是就能让时间开销大幅度减少了?是的,请看下期《并查集的 Rank 秩优化》。

References

[1] LeetCode-547 朋友圈: https://leetcode-cn.com/problems/friend-circles/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员维他命 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
并查集详解(原理+代码实现+应用+优化)
我们可以用vector存名字数组里面的数据,那下标就可以做它们的编号,那这样用编号找名字是很方便的,编号是几,就找下标为几的元素就行了。 但是名字找编号就有点麻烦,所以我们可以借助map给名字和编号建立一个映射关系。
YIN_尹
2024/01/23
5K1
并查集详解(原理+代码实现+应用+优化)
Union-Find 并查集算法详解
今天讲讲 Union-Find 算法,也就是常说的并查集算法,主要是解决图论中「动态连通性」问题的。名词很高端,其实特别好理解,等会解释,另外这个算法的应用都非常有趣。
帅地
2019/12/11
1.1K0
Union-Find 并查集算法详解
【算法提高班】并查集
关于并查集的题目不少,官方给的数据是 30 道(截止 2020-02-20),但是有一些题目虽然官方没有贴并查集标签,但是使用并查集来说确非常简单。这类题目如果掌握模板,那么刷这种题会非常快,并且犯错的概率会大大降低,这就是模板的好处。
lucifer210
2020/02/26
5170
数据结构之并查集
并查集(Union Find),从字面意思不太好理解这东西是个啥,但从名字大概可以得知与查询和集合有关,而实际也确实如此。并查集实际上是一种很不一样的树形结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。
端碗吹水
2021/02/02
1.1K0
04-树5. File Transfer--并查集
  对于一个集合常见的操作有:判断一个元素是否属于一个集合;合并两个集合等等。而并查集是处理一些不相交集合(Disjoint Sets)的合并及查询问题的有利工具。 并查集是利用树结构实现的。一个集合用一棵树来表示,而多个集合便是森林。并查集中的“并”是将两个集合合并即两棵树合并成一颗树;“查”是查找一个元素属于哪个集合,即查找一个节点属于哪棵树。思路如下: 查:通过节点找寻父节点,一直向上查找直到根节点,返回根节点,而根节点代表唯一的那棵树; 并:先查找到两个节点所在的树,如果在同一棵树中(即查找到的根
llhthinker
2018/01/24
6390
LeetCode547题 朋友圈(并查集)
班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。
SakuraTears
2022/01/13
7620
并查集(Union Find)
 没想到有一天我也能搞懂并查集,orz......实际上本文算是《Algorithms》一书的读后感
mathor
2018/07/24
1.1K0
并查集(Union Find)
有一种算法叫做“Union-Find”?
  不少搞IT的朋友听到“算法”时总是觉得它太难,太高大上了。今天,跟大伙儿分享一个比较俗气,但是却非常高效实用的算法,如标题所示Union-Find,是研究关于动态连通性的问题。不保证我能清晰的表述并解释这个算法,也不保证你可以领会这个算法的绝妙之处。但是,只要跟着思路一步一步来,相信你一定可以理解它,并像我一样享受它。
云海谷天
2022/08/09
2740
有一种算法叫做“Union-Find”?
[每日算法] 并查集数据结构及其实例-- day15
并查集是简洁而优雅的数据结构之一,主要用于解决一些元素分组的问题。它管理一系列不相交的集合,并支持两种操作:
苏州程序大白
2022/09/16
2890
[每日算法] 并查集数据结构及其实例-- day15
并查集(Union Find)
  我们之前讲的树结构,都是由父亲节点指向孩子节点,而并查集却是由孩子指向父亲的这样一种数据结构。
程序员波特
2024/01/19
2100
并查集(Union Find)
136页才写了两个算法……难怪劝退新人
今天我们继续来解读《算法》这本书,我将会按照书中的顺序来依次来介绍算法。今天介绍的是本书的第二个算法——并查集。
TechFlow-承志
2022/09/21
3320
136页才写了两个算法……难怪劝退新人
Union-Find 算法怎么应用?
上篇文章 Union-Find 并查集算法详解 很多读者对于 Union-Find 算法的应用表示很感兴趣,这篇文章就拿几道 LeetCode 题目来讲讲这个算法的巧妙用法。
labuladong
2021/09/23
5280
零基础学并查集算法
并查集是我暑假从高手那里学到的一招,觉得真是太精妙的设计了。以前我无法解决的一类问题竟然可以用如此简单高效的方法搞定。不分享出来真是对不起party了。(party:我靠,关我嘛事啊?我跟你很熟么?) 来看一个实例,杭电1232畅通工程 首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。像畅通工程这题,问还需要修几条路,
Angel_Kitty
2018/04/08
1.3K0
零基础学并查集算法
快速搞定并查集
并查集被很多人认为是最简洁而优雅的数据结构之一,主要用于解决一些元素分组的问题。比如最小生成图里的克鲁斯卡尔算法就用的此知识点。它管理一系列不相交的集合,并支持两种操作:
sowhat1412
2020/11/05
5890
快速搞定并查集
并查集专题
关于并查集的题目不少,官方给的数据是 30 道(截止 2020-02-20),但是有一些题目虽然官方没有贴并查集标签,但是使用并查集来说确非常简单。这类题目如果掌握模板,那么刷这种题会非常快,并且犯错的概率会大大降低,这就是模板的好处。
lucifer210
2020/05/09
5390
并查集专题
四十行代码搞定经典的并查集算法
首先我们来解释一下这个数据结构的名称,并查集其实是一个缩写,并指的是合并,查指的是查找,集自然就是集合。所以并查集的全称是合并查找集合,那么顾名思义,这是一个用来合并、查找集合的数据结构。
TechFlow-承志
2020/05/05
7570
算法原理系列:并查集
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014688145/article/details/72830661
用户1147447
2019/05/26
4820
算法动画秒懂并查集
并查集是一种很常用的数据结构,LeetCode上面有二十多道题,这次我们来看一道入门题目LeetCode 547 省份数量。
ACM算法日常
2021/04/22
4470
利用Python实现Union-Find算法
Union-Find(又称 并查集)是一种高效解决 动态连通性问题 的算法。它主要提供两种操作:
华科云商小徐
2025/01/10
1370
每天都刷朋友圈,那你知道并查集吗?
微信大概是我们每天必须接触的一个APP之一,公交上、地铁上、工作休息时,刷刷朋友圈,看看好友当天经历了什么。相较于QQ,微信的一个特点之一就是:除非好友的好友也是你的好友,否则你在朋友圈里看不到好友的好友对好友朋友圈的点赞和评论。
用户6557940
2022/07/24
6280
每天都刷朋友圈,那你知道并查集吗?
相关推荐
并查集详解(原理+代码实现+应用+优化)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档