实用数据结构【并查集】 - 原理
创始人
2024-01-26 18:22:48
0

实用数据结构【并查集】 - 原理

[一个问题]

若某个部落过于庞大,则部落成员见面也有可能不认识。

已知某个部落的成员关系图,任意给出其中两个人,判断是否有亲戚关系。规定:①若x、y 是亲戚,y 和z 是亲戚,则x 和z 也是亲戚;②若x、y是亲戚,则x 的亲戚也是y 的亲戚,y 的亲戚也是x 的亲戚。

如何才能快速判断两个人是否有亲戚关系呢?

以上规定中的第①条是传递关系,第②条相当于两个集合的合并,因此对该问题可以采用并查集轻松解决。

并查集是一种树形数据结构,用于处理集合的合并查询问题。

【算法步骤】

① 初始化。

将每个节点所在的集合号都初始化为其自身编号。

② 查找。

查找两个元素所在的集合,即找祖宗。查找时,采用递归的方法找其祖宗,找到祖宗(集合号等于自身)时停止;然后回归,回归时将祖宗到当前节点路径上的所有节点都统一为祖宗的集合号。

③ 若两个节点的集合号不同,则将两个节点合并为一个集合,合并时只需将一个节点的祖宗集合号修改为另一个节点的祖宗集合号。擒贼先擒王,只改祖宗即可!

【举个栗子】

假设现在有7个人,首先输入亲戚关系图,然后判断两个人是否有亲戚关系。

① 初始化

在这里插入图片描述

② 查找。

输入亲戚关系2、7,查找到2的集合号为2,7的集合号为7。

③ 合并。

两个元素的集合号不同,将两个元素合并为一个集合。在此约定将小的集合号赋值给大的集合号, 因此修改fa[7]=2。

在这里插入图片描述

④ 查找。

输入亲戚关系4、5,查找到4的集合号为4,5的集合号为5。

⑤ 合并。两个元素的集合号不同,将两个元素合并为一个集合,修改fa[5]=4。

在这里插入图片描述

⑥ 查找。输入亲戚关系3、7,查找到3的集合号为3,7的集合号为2。

⑦ 合并。两个元素的集合号不同,将两个元素合并为一个集合,修改fa[3]=2。

在这里插入图片描述

⑧ 查找。输入亲戚关系4、7,查找到4的集合号为4,7的集合号为2。

⑨ 合并。两个元素的集合号不同,将两个元素合并为一个集合,修改fa[4]=2。

在这里插入图片描述

擒贼先擒王,只改祖宗即可!有两个节点的集合号为4,只需修改两个节点中的祖宗,无须将集合号为4的所有节点都检索一遍,这正是并查集的巧妙之处!

⑩ 查找。输入亲戚关系3、4,查找到3的集合号为2,4的集合号为2。

⑪ 合并。两个元素的集合号相同,无须合并。

⑫ 查找。输入亲戚关系5、7,查找到7的集合号为2,查找到5的集合号不等于5,所以找5的祖宗。首先找到其父节点4,4的父节点为2,2的集合号等于2(祖宗),搜索停止。返回时,将祖宗到当前节点路径上所有节点的集合号都统一为祖宗的集合号。更新5的集合号为祖宗的集合号2。

在这里插入图片描述

⑬ 合并。两个元素的集合号相同,无须合并。

⑭ 查找。输入亲戚关系5、6,查找到5的集合号为2,6的集合号为6。

⑮ 合并。两个元素的集合号不同,将两个元素合并为一个集合,修改fa[6]=2。

在这里插入图片描述

⑯ 查找。输入亲戚关系2、3,查找到2的集合号为2,3的集合号为2。

⑰ 合并。两个元素的集合号相同,无须合并。

⑱ 查找。输入亲戚关系1、2,查找到1的集合号为1,2的集合号为2。两个元素的集合号不同,将两个元素合并为一个集合,修改fa[2]=1。

在这里插入图片描述

OK。假设到此为止,亲戚关系图已经输入完毕。可以看到3、4、5、6、7这些节点的集合号并没有被修改为1,这样做真的可以吗?

现在,判断5和2是不是亲戚关系,则过程如下。

① 查找到5的集合号为2,5的集合号不等于5,找其祖宗。首先查找到5的父节点2,2的父节点1,1的集合号为1(祖宗),搜索停止。将祖宗1到5这条路径上所有节点的集合号都更新为1。

② 查找到2的集合号为1,找其祖宗。2的祖宗为1,1的集合号为1(祖宗),搜索停止。将祖宗1到2这条路径上所有节点的集合号都更新为1。

③ 5和2的集合号都为1,因此5和2是亲戚关系。

【算法实现】

① 初始化。将节点i 的集合号初始化为其自身编号。

void init(){ //初始化集合号for(int i = 1; i <= n ; i ++){fa[i] = i; //把节点i 的集合号初始化为其 自身编号}
}

② 查找。查找两个元素所在的集合,即找祖宗。查找时,采用递归的方法找其祖宗(集合号等于自身)。回归时,将祖宗到当前节点路径上的所有节点都统一为祖宗的集合号。

void Find(int x){ //查找if(x != fa[x]){fa[x] = Find(fa[x]);	}return fa[x];
}

fa[x ]表示x 的集合号,若x !=fa[x ],则说明x 节点不是祖宗。继续向上找,找到祖宗后返回。回归时将祖宗到当前节点路径上的所有节点都统一为祖宗的集合号,如下图所示。

在这里插入图片描述

③ 合并。先找到x 的集合号a ,y 的集合号b ,若a 和b 相等,则无须合并。若a 和b 不相等,则将a 的集合号修改为b ,或者将b 的集合号修改为a 。擒贼先擒王,只改祖宗即可

void Union(int x, int y){ //合并int a = Find(x);int b = Find(y);if(a != b){fa[b] = a;}
}

输入1和8的亲戚关系,先找到1的祖宗2,8的祖宗6,将6的集合号修改为2即可。

在这里插入图片描述

【算法分析】

若有n 个节点、e 条边(关系),则每条边(u , v )进行集合合并时,都要查找u 和v 的祖宗,查找的路径为从当前节点一直到根节点,n 个节点组成的树的平均高度为logn ,因此并查集中,合并集合的时间复杂度为O (e logn )。

相关内容

热门资讯

大学生创业利大于弊 大学生创业... 大学生创新创业利弊大学生创业利大于弊2辩大学生毕业后创业的利与弊大学生自主创业的利弊大学生创业好还是...
谈大学生创业(大学生创业的利和... 大学生创新创业利弊大学生创业利大于弊2辩大学生毕业后创业的利与弊大学生自主创业的利弊大学生创业好还是...
创业加盟网下载 投资加盟 创业... 加盟店投资加盟商机网小店加盟项目创业加盟网站排行榜加盟项目全国免费代理商加盟创业商机网2021中国特...
深圳湾创业广场 深圳湾创业广场... 深圳湾一号深圳投资公司实力排行榜深圳海上世界双玺花园华侨城绿景美景广场深圳设计之都创意产业园区块链创...
植物有故事:40亿年的创业史百... 《创业史》人物关系梳理图创业史生宝和谁结婚了创业史pdf创业史第一部内容简介创业史中的徐改霞创业史一...
网上创业该如何选择方向? 关于... 免费挖矿赚钱网站大全创业网站关于创业的软件有哪几个2021年创业适合做什么创业平台有哪些适合17岁学...
网上万元创业项目靠谱吗 适合1... 免费挖矿赚钱网站大全创业网站关于创业的软件有哪几个2021年创业适合做什么创业平台有哪些适合17岁学...
鲜果时间店加盟,上海总部支持让... 好的加盟创业项目创业小项目创业网加盟网上海创业落户创业商机网加盟什么店最赚钱代理商加盟冰雪皇后吕约小...
创业软件 创业软件 创业软件公... 加盟58同镇能挣钱吗手机创业项目有哪些手机上正规的赚钱渠道没人注意的暴利行业没人愿意干的68个暴利行...
俞敏洪创业演讲 俞敏洪创业演讲... 创业路上的艰辛演讲稿艰辛创业成功演讲稿中国创业榜样俞敏洪演讲俞敏洪演讲内容俞敏洪 关于勇气的演讲关于...