Union-find 并查集
解决问题
给一系列对点0~N-1的连接,判断某两个点p与q是否相连。
private int[] id; // 判断p和q是否属于同一个连通分量
public boolean connected(int p, int q) // 连接两个点
public void union(int p, int q)
Quick-find
connected(p, q):判断p 和 q 的id值是否相同
union(p, q): 将与p 的id 相同的所有点都改为q的id
缺点:union太慢,需要遍历id数组
Quick-union
connected(p, q):判断p 和 q 的根的id值是否相同
union(p, q): 将与p 的根的 id 改为q的根的 id
本质上是将并查集之间的关系看做一棵树
缺点:最坏情况下仍然需要遍历数组
Weighted Quick-union
connected(p, q):判断p 和 q 的根的id值是否相同
union(p, q): 判断p和q所在的树哪个大(包含的节点多),将较小的树根的 id 改为较大的树根的 id
某个节点高度增加1,当且仅当它在一颗小树T1上且被union并入大树T2中,生成的树节点数大于T1的两倍,所以某个节点的高度最多只能是lg(N)
Weighted Quick-union with Path Compression
connected(p, q):判断p 和 q 的根的id值是否相同
union(p, q): 判断p和q所在的树哪个大(包含的节点多),将较小的节点到较小的树根这条路径上所有节点的 id 改为较大的树根的 id
总结
四种方法复杂度如下,其中lg* 表示需要取对数多少次才能将N的值变为≤1,WQUPC复杂度是由论文中所得,lg*可以视为常数复杂度。
| algorithm | 初始化 | union | connected |
| quick find | N | N | 1 |
| quick union | N | N | N |
| weighted quick union | N | lg N | lg N |
| weighted quick union with path compression | N | lg* N | lg* N |
实现
public class UF {
private int[] parent; // parent[i] = parent of i
private byte[] rank; // rank[i] = rank of subtree rooted at i (never more than 31) 记录的是树的高度
private int count; // number of components
/**
* Initializes an empty union-find data structure with <tt>N</tt> sites
* <tt>0</tt> through <tt>N-1</tt>. Each site is initially in its own
* component.
*
* @param N the number of sites
* @throws IllegalArgumentException if <tt>N < 0</tt>
*/
public UF(int N) {
if (N < 0) throw new IllegalArgumentException();
count = N;
parent = new int[N];
rank = new byte[N];
for (int i = 0; i < N; i++) {
parent[i] = i;
rank[i] = 0;
}
}
/**
* Returns the component identifier for the component containing site <tt>p</tt>.
*
* @param p the integer representing one site
* @return the component identifier for the component containing site <tt>p</tt>
* @throws IndexOutOfBoundsException unless <tt>0 ≤ p < N</tt>
*/
public int find(int p) {
validate(p);
while (p != parent[p]) {
parent[p] = parent[parent[p]]; // path compression by halving 【完成路径压缩】
p = parent[p];
}
return p;
}
/**
* Returns the number of components.
*
* @return the number of components (between <tt>1</tt> and <tt>N</tt>)
*/
public int count() {
return count;
}
/**
* Returns true if the the two sites are in the same component.
*
* @param p the integer representing one site
* @param q the integer representing the other site
* @return <tt>true</tt> if the two sites <tt>p</tt> and <tt>q</tt> are in the same component;
* <tt>false</tt> otherwise
* @throws IndexOutOfBoundsException unless
* both <tt>0 ≤ p < N</tt> and <tt>0 ≤ q < N</tt>
*/
public boolean connected(int p, int q) {
return find(p) == find(q);
}
/**
* Merges the component containing site <tt>p</tt> with the
* the component containing site <tt>q</tt>.
*
* @param p the integer representing one site
* @param q the integer representing the other site
* @throws IndexOutOfBoundsException unless
* both <tt>0 ≤ p < N</tt> and <tt>0 ≤ q < N</tt>
*/
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) return;
// make root of smaller rank point to root of larger rank
if (rank[rootP] < rank[rootQ]) parent[rootP] = rootQ;
else if (rank[rootP] > rank[rootQ]) parent[rootQ] = rootP;
else {
parent[rootQ] = rootP;
rank[rootP]++; //【只有此处才增加联通分量的rank】
}
count--;
}
// validate that p is a valid index
private void validate(int p) {
int N = parent.length;
if (p < 0 || p >= N) {
throw new IndexOutOfBoundsException("index " + p + " is not between 0 and " + (N-1));
}
}
/**
* Reads in a an integer <tt>N</tt> and a sequence of pairs of integers
* (between <tt>0</tt> and <tt>N-1</tt>) from standard input, where each integer
* in the pair represents some site;
* if the sites are in different components, merge the two components
* and print the pair to standard output.
*/
public static void main(String[] args) {
int N = StdIn.readInt();
UF uf = new UF(N);
while (!StdIn.isEmpty()) {
int p = StdIn.readInt();
int q = StdIn.readInt();
if (uf.connected(p, q)) continue;
uf.union(p, q);
StdOut.println(p + " " + q);
}
StdOut.println(uf.count() + " components");
}
}
Union-find 并查集的更多相关文章
- <算法><Union Find并查集>
Intro 想象这样的应用场景:给定一些点,随着程序输入,不断地添加点之间的连通关系(边),整个图的连通关系也在变化.这时候我们如何维护整个图的连通性(即判断任意两个点之间的连通性)呢? 一个比较简单 ...
- 并查集(Union/Find)模板及详解
概念: 并查集是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图.求最小生成树的Kruskal 算法和求最近公共祖先等. 操作: 并查集的基本操作有两个 ...
- 并查集(Union Find)的基本实现
概念 并查集是一种树形的数据结构,用来处理一些不交集的合并及查询问题.主要有两个操作: find:确定元素属于哪一个子集. union:将两个子集合并成同一个集合. 所以并查集能够解决网络中节点的连通 ...
- 并查集 (Union Find ) P - The Suspects
Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized ...
- 并查集(Disjoint Set Union,DSU)
定义: 并查集是一种用来管理元素分组情况的数据结构. 作用: 查询元素a和元素b是否属于同一组 合并元素a和元素b所在的组 优化方法: 1.路径压缩 2.添加高度属性 拓展延伸: 分组并查集 带权并查 ...
- 第三十一篇 玩转数据结构——并查集(Union Find)
1.. 并查集的应用场景 查看"网络"中节点的连接状态,这里的网络是广义上的网络 数学中的集合类的实现 2.. 并查集所支持的操作 对于一组数据,并查集主要支持两种操作:合并两 ...
- 并查集(不相交集)的Union操作
在并查集(不相交集)中附加操作\(Deunion\),它实现的功能是取消最后一次\(Union\)的操作. 实现思想 初始化一个空栈,将每一次的\(Union\)操作的两个集合的根和其值\(Push\ ...
- Mutual Training for Wannafly Union #6 E - Summer Trip(并查集)
题目链接:http://www.spoj.com/problems/IAPCR2F/en/ 题目大意: 给m个数字代表的大小,之后n组数据,两两关联,关联后的所有数字为一组,从小到大输出组数以及对应的 ...
- POJ 1611 The Suspects 并查集 Union Find
本题也是个标准的并查集题解. 操作完并查集之后,就是要找和0节点在同一个集合的元素有多少. 注意这个操作,须要先找到0的父母节点.然后查找有多少个节点的额父母节点和0的父母节点同样. 这个时候须要对每 ...
- 图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用
图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 ...
随机推荐
- RF脚本中的坑2: pip下载python库时报certificate verify failed
用pip命令下载第三方library时,报错certificate verify failed,截图如下: 在网上找了各种教程,包括修改了pip下载源地址也无效果,最后祭出了杀手锏——FQ,FQ成功后 ...
- 【转载】#438 - Benefits of Using Interfaces
You might wonder why you'd define an interface, have a class implement that interface and then acces ...
- Ubuntu 12.04 安装Chrome步骤
一.添加PPA 从Google Linux Repository(http://www.google.com/linuxrepositories/)下载安装Key,或把下面的代码复制进终端,回车,需要 ...
- NodeJS服务器端平台实践记录
[2015 node.js learning notes]by lijun 01-note Nodejs是服务器端的javascript,是一种单线程.异步I/O.事件驱动型的javascript:其 ...
- "应用程序无法正常启动(0xc000007b)。请单击 确定 关闭应用程序。"解决方法
完成一小项目,正常运行,测试环境有Windows XP,Win 7,Win X64及有SP的版本,也是我客户端可能用到的系统版本,Win8和Win10未测试 但在分发过程中,发现有的机器可以正常运行, ...
- 创建properties文件保存在WEB项目的classes文件下
1.保存数据 private synchronized boolean saveFile(String url,String filename){ try { String path = servle ...
- PL/SQL规范、块、过程、函数、包、触发器
1.pl/sql规范 标识符号的命名规范 1) 定义变量,用 v- 作为前缀 v-sal 2)定义常亮, 用 c- 作为前缀 c-rate 3) 定义游标,用 cursor作为后缀 emp_curso ...
- Restframework的版本及分页
1.版本 1.1基于url的get传参方式 1.创建django项目(起名我的是version),再创建一个app01应用 创建完成,通过python3 manage.py startapp api ...
- js前台加密,java后端解密
1.前台JS <script type="text/javascript"> $(function() { $(" ...
- [SCOI2009]windy数(数位DP)
题目描述 windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道, 在A和B之间,包括A和B,总共有多少个windy数? 输入输出格式 输 ...