笔试算法题(38):并查集(Union-Find Sets)
议题:并查集(Union-Find Sets)
分析:
一种树型数据结构,用于处理不相交集合(Disjoint Sets)的合并以及查询;一开始让所有元素独立成树,也就是只有根节点的树;然后根据需要将关联的元素(树)进行合并;合并的方式仅仅是将一棵树最原始的节点的父亲索引指向另一棵树;
优化:加入一个rank数组存储节点深度的下界(从当前节点到其最远子节点的距离),从而可以启发式的对树进行合并,从而减少树的深度,防止树的退化;使 得包含较少节点的树根指向包含较多节点的树根,具体指代为树的高度;另一个优化就是路径压缩,尽可能将子节点都直接连接到根节点之后;
并查集的空间复杂度为O(N),构建一个集合的时间复杂度为O(N);压缩后的查找复杂度是一个很小的常数;应用:Kruskal算法求最小生成树中判断新加入的边是否在同一棵树内部;两个节点的最近公共祖先(Least Common Ancestors);
初始化father:各个节点独立成树,并且其father[i]=i,也就是其父节点就是其自身;
father[i]
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9初始化rank:各个节点为根节点,所以高度都为1;
rank[i]
0 1 2 3 4 5 6 7 8 9
1 1 1 1 1 1 1 1 1 1合并2和6:由于rank[2]=rank[6],所以将2的父亲索引指向6,这样2和6就在同一棵树;并需将6的rank值增加1;
father[i]
0 1 2 3 4 5 6 7 8 9
0 1 6 3 4 5 6 7 8 9
rank[i]
0 1 2 3 4 5 6 7 8 9
1 1 1 1 1 1 2 1 1 1
样例:
int *father;
int *rank; /**
* 并查集的初始化:
* 数组father中的元素在最开始ide时候都是独立的树,也就是只有根节点
* 的树,数组father的下标i表示节点,而father[i]的值表示i节点的父亲
* 节点;rank[i]=1表示一开始所有树节点的高度都为1
* */
void init(int cap) {
father=new int[cap];
rank=new int[cap];
/**
* 时间复杂度为O(N)
* */
for(int i=;i<;i++) {
father[i]=i;
rank[i]=;
}
} void clean() {
delete [] father;
delete [] rank;
}
/**
* 查找元素所在的集合并进行路劲压缩:
* 由于需要频繁使用GetFather()函数,并且其时间复杂度受树结构影响;
* 当元素较多的时候,集合退化成链表,则GetFather()需要O(N),所以
* 需要对其进行优化,每次调用GetFather()的时候都将输入元素压缩成
* 最原始父亲节点的直接子节点
* */
int GetFather(int son) {
if(father[son]==son)
return son;
else {
father[son]=GetFather(father[son]);
return father[son];
}
} /**
* 合并两个不相交的集合:
* 输入元素x和y来自两个不相交的集合,找到其最原始的父亲节点
* 并将一个原始父亲节点设置为另一个原始父亲节点的父亲节点
* */
void Union1(int x, int y) {
/**
* GetFather()为递归寻找输入节点的最原始的父亲节点
* */
int fx=GetFather(x);
int fy=GetFather(y);
/**
* 判断x和y是否来自同一棵树,如果不是才进行赋值;其实可以
* 不同进行判断(省去if语句)
* 注意最原始父亲节点的father[i]=i;
* */
if(fx!=fy)
father[fx]=fy;
} /**
* 利用rank加权数组启发式进行合并
* */
void Union2(int x, int y) {
int fx=GetFather(x);
int fy=GetFather(y); if(fx==fy) return;
/**
* rank[fx]较大,说明其越靠近根节点,则将
* fy连接到其后面可以压缩路径
* */
if(rank[fx]>rank[fy])
father[fy]=fx;
else {
if(rank[fx]==rank[fy])
rank[fy]++;
father[fx]=fy;
}
} /**
* 判断两个元素是否属于同一个集合:
* 利用GetFather()函数判断其最原始父亲节点是否相同
* */
bool IsSameSet(int x, int y) {
return GetFather(x)==GetFather(y);
}
笔试算法题(38):并查集(Union-Find Sets)的更多相关文章
- 并查集(Union/Find)模板及详解
概念: 并查集是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图.求最小生成树的Kruskal 算法和求最近公共祖先等. 操作: 并查集的基本操作有两个 ...
- hdu 4641 K-string SAM的O(n^2)算法 以及 SAM+并查集优化
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4641 题意:有一个长度为n(n < 5e4)的字符串,Q(Q<=2e5)次操作:操作分为:在末 ...
- hdu 1233(还是畅通project)(prime算法,克鲁斯卡尔算法)(并查集,最小生成树)
还是畅通project Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tota ...
- 前端如何应对笔试算法题?(用node编程)
用nodeJs写算法题 咱们前端使用算法的地方不多,但是为了校招笔试,不得不针对算法题去练习呀! 好不容易下定决心 攻克算法题.发现js并不能像c语言一样自建输入输出流.只能回去学习c语言了吗?其实不 ...
- PAT甲题题解-1107. Social Clusters (30)-PAT甲级真题(并查集)
题意:有n个人,每个人有k个爱好,如果两个人有某个爱好相同,他们就处于同一个集合.问总共有多少个集合,以及每个集合有多少人,并按从大到小输出. 很明显,采用并查集.vis[k]标记爱好k第一次出现的人 ...
- POJ 2421 Constructing Roads (Kruskal算法+压缩路径并查集 )
Constructing Roads Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 19884 Accepted: 83 ...
- 笔试算法题(50):简介 - 广度优先 & 深度优先 & 最小生成树算法
广度优先搜索&深度优先搜索(Breadth First Search & Depth First Search) BFS优缺点: 同一层的所有节点都会加入队列,所以耗用大量空间: 仅能 ...
- [Comet OJ - Contest #6 D][48D 2280]另一道树题_并查集
另一道树题 题目大意: 数据范围: 题解: 这个题第一眼能发现的是,我们的答案分成两种情况. 第一种是在非根节点汇合,第二种是在根节点汇合. 尝试枚举在第几回合结束,假设在第$i$回合结束的方案数为$ ...
- hdu 4641K-string SAM的O(n^2)算法 以及 SAM+并查集优化
转载:http://www.cnblogs.com/hxer/p/5675149.html 题意:有一个长度为n(n < 5e4)的字符串,Q(Q<=2e5)次操作:操作分为:在末尾插入一 ...
随机推荐
- 简单水题 POJ 2291 Rotten Ropes
题目传送门 /* 我校oj的源题,看懂题意就很水,贴出来省的再敲:) */ #include <cstdio> #include <algorithm> #include &l ...
- JEECMS9.3集成dubbo操作记录
需求描述: 门户及其他应用系统需要查询JEECMS9.3中发布的栏目及数据,而其他系统都是基于dubbo开发的,因此想要将JEECMS9.3中集成dubbo并对外提供内容管理服务. 需求实现: 1.添 ...
- Styles and Themens(3)android所有主题表
The Android platform provides a large collection of styles and themes that you can use in your appli ...
- html下的图片链接有边框的解决方法
使用dreamweaver创建网页后,上传到网站发现网页的图片链接有非常难看的蓝色边框,而在dw下是没有的 后来查看了一下网上的资料,发现加一个border="0"即可,默认是有边 ...
- java中实参与形参的概念
形参: public void fun(形参类型 形参名){ ... } 实参: public static void main(String[] args){ 类 对象名=new 类(); 对象名. ...
- gcc 编译 c++ 程序(转载)
单个源文件生成可执行程序 下面是一个保存在文件 helloworld.cpp 中一个简单的 C++ 程序的代码: /* helloworld.cpp */ #include <iostream& ...
- RabbitMQ四:生产者--队列--消费者
AMQP协议的梳理和名词解析 建议先把上篇AMQP协议先看一遍,理解一下,由于用XMind绘图,电脑屏幕比较小,不能截取全部,如果想要全图和源代码,请下面留言....... 可以点击图片,打开到新的 ...
- Webform 内置对象 Session对象、Application全局对象,ViewState
Session 每台电脑访问服务器,都有独立的session,key值都一样,内容不一样. 1.session保存在服务器上. 2.session没有持久性,保存周期就是20分钟. 重点: sessi ...
- 工作记录:JS正则表达式 angularjs ng-if ng-show ng-switch
用了一下JS 正则表达式判断密码,很简单 学习了angularjs的ng-if ng-show ng-switch的区别并使用 https://www.cnblogs.com/54td/p/59743 ...
- [BZOJ1798][AHOI2009]Seq维护序列 线段树
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1798 一眼看过去线段树,事实上就是线段树.对于乘和加的两个标记,我们可以规定一个顺序,比如 ...