博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
普通并查集
阅读量:6114 次
发布时间:2019-06-21

本文共 1864 字,大约阅读时间需要 6 分钟。

简介

在平时的计算中,常常会遇到集合划分的问题,例如一个集合S={a1,a2,a3,a4},按照一定规则我们可以划分为S1={a1,a2},S2={a3},s3={a4}。但是在划分好集合后,又该如何快速确认任意两个元素之间的关系呢。由此引出并查集。


并查集简介

并查集最关键的表现就是一个集合中的每一个元素都有一个共同的集合代表元素,也就是集合的boss。判断两个元素是否为同一个集合的条件便是二者的boss是否为一个人。而合并两个集合,只需要将两个集合所有元素的最终boss都设成同一个元素。

由此:并查集需要两个关键函数

  • find()查找元素集合
  • union()合并集合

先用图感受一下思路:

1.现在每个元素都是一家公司,它们各自都是自己的boss。

1329608-20181202160317458-1518442208.png

2.公司1和公司5志趣相投,决定合作。一番商讨,决定5来当boss。

1329608-20181202160328220-760010286.png

3.公司3和公司4见状,两手一拍,不行!我们也得合作和那两家伙干,3当了boss。

1329608-20181202160337811-1856686068.png

4.公司6看腥风血雨,正好和公司4有点交情,想来寻求庇护,4成为了6的boss,3成为了第一个大boss。

1329608-20181202160348525-1908691118.png

5.底下其乐融融,3和5左思右想觉得再这么对着干下去不如来一波和谐的py交易,说时迟那时快,3,5决定合体!但boss只能有一个,3有管理经验,3变成了5的boss。

1329608-20181202160358402-289373774.png

6.公司2的消息不灵通,市场巨变,还在自嗨,反应过来的时候,想着去求助1和6,二者告诉他他们的boss分别是5和4,2又去找5和4,发现他们的boss都是3。哦!原来都是一家人,3啊,我要做你小弟啊!

1329608-20181202160406015-1668688453.png

PS:然后他们就因为垄断被罚款了。


代码实现

就先来实现最简单的。

定义

int boss[1000];//这个数组记录的每个公司的boss是谁

Find

int find(int x) {    while (boss[x] != x) x = boss[x];//如果x的boss不是x自己,那么就去找x的boss    return x;}

Union

void union(int x, int y) {    int tx = find(x);//找到x的boss    int ty = find(y);//找到y的boss    if (x != y) boss[x] = y;//不是一个boss,你就当我的boss    else return;}

一个简单的并查集就实现了,但是这样实现的并查集树状结构不可控,一个一字长蛇阵就可以让查询的效率变得很低,所以我们希望所有子公司可以直接找到最终的boss。这就是路径压缩算法。在n次ufind的时间复杂度上界为O(n\(\alpha\)(n)),\(\alpha\)(n)是阿克曼函数的反函数。

1329608-20181202160429397-2010470039.png1329608-20181202160443265-577936465.png
我们先修改find函数

Find_zwei

int find_zwei(int x) {    if (boss[x] == x) return x;    return boss[x] = find_zwei(boss[x]);//你的boss就是我的boss,my~my~my~my~my~}

我们还可以改造union函数,进一步优化这个树状结构。我们引入一个rank数组表示每一个元素的高度,初始为1。

定义_zwei

int boss[1000];int rank[1000];

Union_zwei

void union_zwei(int x, int y) {    int tx = find_zwei(x);    int ty = find_zwei(y);    if (tx == ty) return;    if (rank[tx] > rank[ty]) boss[ty] = tx;//tx的高度大于ty的高度,也就是tx为2,ty为1的时候    else {        if (rank[tx] == rank[ty]) {//二者高度相同的时候必然会增加高度            rank[ty]++;        }        boss[tx] = ty;    }}

初始化

void init(int n) {    for (int i = 1; i <= n; i++) {        boss[i] = i;        rank[i] = 1;    }}

至此,就是普通并查集。后续再讲带权并查集。

转载于:https://www.cnblogs.com/pullself/p/10053829.html

你可能感兴趣的文章
【WP 8.1开发】文件选取器的使用方法
查看>>
Java实现BASE64编解码
查看>>
【Java】java基本知识
查看>>
之前学习wordpress的几张图片
查看>>
RT-Thread下的串口驱动程序分析【转载】
查看>>
UITableView的UITableViewStyleGrouped
查看>>
ecshop中getAll ,getOne ,getRow的区别
查看>>
Apple 企业开发者账号申请记录
查看>>
ecshop后台权限增加
查看>>
C#装饰者模式实例代码
查看>>
ASP.NET MVC显示异常信息
查看>>
第 9 章 MySQL数据库Schema设计的性能优化
查看>>
前nginx后Apache+Node反向代理
查看>>
Web前端开发十日谈
查看>>
luov之SMTP报错详解
查看>>
软件概要设计做什么,怎么做
查看>>
dwr
查看>>
java的特殊符号
查看>>
word2010中去掉红色波浪线的方法
查看>>
fabric上下文管理器(context mangers)
查看>>