并查集(2)-按秩合并和路径压缩
在上面一讲是并查集(1)-判断无向图是否存在环. 我们使用了并查集的两个操作: union() 和 find()
// find 的原始实现 int find(int parent[], int i) {if (parent[i] == -1)return i;return find(parent, parent[i]); }// union()的原始实现 void Union(int parent[], int x, int y) {int xset = find(parent, x);int yset = find(parent, y);parent[xset] = yset; }
上述union()和find()是直接的,最坏的情况下的时间复杂度是线性的。表示子集的树可能会倾斜,像一个链表。下面是一个例子最坏情况的场景。
假设有4个元素 0, 1, 2, 3 初始化 0 1 2 3 Do Union(0, 1)1 2 3 /0Do Union(1, 2)2 3 /1/ 0Do Union(2, 3)3 /2/1/ 0
以上操作可以优化到O(Log n)在最糟糕的情况下。方法就是在每次合并都把深度较小的集合合并在深度较大的集合下面 。这种技术被称为按秩合并。这样可以防止树的退化,最坏情况不会出现。
继续用上面的例子 0 1 2 3 Do Union(0, 1)1 2 3 /0Do Union(1, 2)1 3/ \ 0 2Do Union(2, 3)1 / | \ 0 2 3
第二个要优化的就是find(). 路径压缩实际上是在找完根结点之后,在递归回来的时候顺便把路径上元素的父亲指针都指向根结点。
假设集合{0, 1, .. 9} 的树表示如下所示: 当调用 find(3)时9/ | \ 4 5 6/ \ / \0 3 7 8/ \1 2 我们向上查找,找到是这个集合的根节点. 路径压缩就是:直接把 3的 父节点 设置为 9 当下次再查找 1, 2 或 3 时,查找的路径就会变短。9/ / \ \4 5 6 3 / / \ / \0 7 8 1 2
这两个优化方法互为补充。每个操作的时间复杂度比O(Logn)要小。事实上,摊销时间复杂度实际上变成了小的常数。
// 用并查集判断是否存在环 #include<stdio.h> #include<stdlib.h> #include<string.h> //图中的边 struct Edge {int dest,src; }; //图结构体 struct Graph { // V-> 顶点个数, E-> 边的个数int V,E;// 每个图就是 边的集合struct Edge *edge; };struct subset {int parent;int rank; }; //创建一个图 struct Graph * createGraph(int V, int E) {struct Graph *graph=(struct Graph *)malloc(sizeof(struct Graph));graph->V=V;graph->E=E;graph->edge=(struct Edge *)malloc(graph->E*sizeof(struct Edge));return graph; }//使用路径压缩 int find(struct subset subsets[],int i) { // 找到 root并使 root 作为 i 的父节点if(subsets[i].parent==i)return i;elsereturn (subsets[i].parent=find(subsets,subsets[i].parent)); }//使用按秩合并 void Union(struct subset subsets[], int x, int y) {int xroot=find(subsets,x);int yroot=find(subsets,y);// 将深度较小的集合 合并到深度大的集合下面if(subsets[xroot].rank<subsets[yroot].rank)subsets[xroot].parent=yroot;else if(subsets[xroot].rank>subsets[yroot].rank)subsets[yroot].parent=xroot;else//深度一样,任选一个,并增加另一个 {subsets[yroot].parent=xroot;subsets[xroot].rank++;} }int isCycle(struct Graph* graph) {int V=graph->V;int E=graph->E;struct subset *subsets=(struct subset *)malloc(V*sizeof(struct subset));for(int i=0;i<V;i++){subsets[i].parent=i;subsets[i].rank=0;}for(int e=0;e<E;e++){int x=find(subsets,graph->edge[e].dest);int y=find(subsets,graph->edge[e].src);if(x==y)return 1;Union(subsets,x,y);}return 0; }int main() {int V=3,E=2;struct Graph *graph=createGraph(V,E);/* 构造以下的图0| \| \1-----2 */graph->edge[0].src=0;graph->edge[0].dest=1;graph->edge[1].src=1;graph->edge[1].dest=2;// graph->edge[2].src=0;//graph->edge[2].dest=3;if(isCycle(graph))printf("Graph contains cycle\n");elseprintf("Graph doesn't contains cycle\n");return 0; }
运行结果如下:
转载于:https://www.cnblogs.com/wuchanming/p/3873847.html
并查集(2)-按秩合并和路径压缩相关推荐
- 22中超联赛day8 1007(hdu7226) Darnassus 并查集(按秩合并+路径压缩)+ 链式前向星桶排 + Kruskal求最小生成树
Darnassus 题目描述 Even the World Tree must bow to the cycle of life. Everything born will die. Archimon ...
- Gym - 101194G Pandaria (并查集+倍增+线段树合并)
题意: 给定一个无向图.每个点有一种颜色.现在给定q个询问,每次询问x和w,求所有能通过边权值不超过w的边走到x的点的集合中,哪一种颜色的点出现的次数最多.次数相同时输出编号最小的那个颜色.强制在线. ...
- 单链表式并查集应用(解决区间合并,区间删除,染色问题)
单链表式并查集应用 普通并查集(树状): p[i]p[i]p[i] 表示节点 iii 的父节点, iii 所在树的根节点是代表元素. 单链表式并查集(单链表状)时间复杂度 O(m元素值域+n)O(m_ ...
- 【数据结构笔记19】File Transfer的C语言实现,集合的简化表示,按秩归并,路径压缩
本次笔记内容: File Transfer - C语言实现(4小节共42:43) 文章目录 集合的简化表示 题意理解与实现 题目与样例 程序框架 简单实现Find与Uion函数 按秩归并改进Union ...
- [并查集][排序][dfs][启发式合并] JZOJ P3635 Peaks
Description 有一个居住在多山岛屿的登山家,已经攀上了一座山峰,并且要攀爬另外一座更高的山峰. 更精确地说,岛上的每一点都有一个大于零的海拔(海面的海拔为零),并且如果登山家位于海拔Ei的山 ...
- 05-树8 File Transfer(并查集)
05-树8 File Transfer 分数 25 作者 陈越 单位 浙江大学 We have a network of computers and a list of bi-directional ...
- 牛客多校8 - All-Star Game(线段树分治+并查集按秩合并的撤销操作)
题目链接:点击查看 题目大意:有 n 个球员和 m 个球迷,一个球员可能是多个球迷的粉丝,需要选择最少的球员进行比赛,使得所有的球迷都愿意观看(对于每个球迷来说,都有至少一个其喜欢的球员入选比赛) 对 ...
- 线段树分治 ---- F. Extending Set of Points(线段树分治 + 可撤销并查集)
题目链接 题目大意: 你有个点集合SSS,每次往集合里面加点或者删点(如果要加的点出现过),如果(x1,y1),(x2,y1),(x1,y2),(x2,y2)(x1,y1),(x2,y1),(x1,y ...
- 0x41.数据结构进阶 - 并查集
目录 一.路径压缩与按秩合并 1.AcWing 237. 程序自动分析(NOIP2015) 二.边带权并查集 1.AcWing 238. 银河英雄传说(边带权并查集模板) 2.AcWing 239. ...
- 【模板/经典题型】并查集维护生成树
这里的并查集是按秩合并并查集. 这种方法维护生成树的时候可以维护一个点到根的权值. 但是由于合并的时候做了一个类似换根一样的操作,因此这个权值通常只能是异或之类的. //find-union-set ...
最新文章
- Akamai CDN技术调研
- 19 条 MySQL 技巧,效率至少提高 3倍!
- python 赋值 浅copy_python – 浅拷贝,deepcopy和正常赋值操作之间的区别是什么?
- [TCP/IP] TCP流和UDP数据报之间的区别
- Java并发编程(五):Java线程安全性中的对象发布和逸出
- C++求复数的角度_人教A版高中数学必修二7.1 复数的概念优质课公开课课件、教案...
- 51nod 1091 重叠的线段(贪心)
- 语音识别学习日志 2019-7-13 语音识别基础知识准备 1{语音基础知识}
- mysql 查看运行级别_运行级别及进程
- JavaScript菜鸽子基础知识总结(一)
- 上传项目到GitLab
- ZOJ1002-Fire Net(深度优先搜索)
- curviloft插件怎么用_Curviloft插件下载
- 基于java的化妆品购物商城微信小程序的设计与实现 毕业设计毕设参考
- ceph最低配置和硬件推荐
- 【windows下基于Eclipse和GCC搭建stm32开发环境(4)】STM32启动过程详解
- eclipse安装tomcat时只有locahost,不显示server name
- EAN-13 条形码编程示例
- android 11如何剪裁上传图片
- [每天一个知识点]12-Maven怎么读
热门文章
- 对数字信号处理中各种频率以及分辨率的理解
- 新举措!ACL系列会议引入滚动审稿机制
- 【NAACL21】老板让我用少量样本 finetune 模型,我还有救吗?急急急,在线等!...
- ACL 2020投稿论文超3000篇,中国投稿量第一,录取率却未进前10
- 本周论文推荐(迁移学习、图神经网络)
- 【推荐系统】推荐系统中的图网络模型
- PHM算法与智能分析技术
- 10分钟就能搭建远程开发环境?你早点怎么不出现(#`n´)!
- 挖掘11亿用户背后的产品逻辑之美
- Exadata中最有用的功能-存储索引