并查集
本书详细阐述了并查集的提出与优化; 从提出到找到最优解, 并查集共经历了四个版本: quick-find, quick-union, 加权quick-union和使用路径压缩的加权quick-union;
1. 并查集概念等等
-
并查集的目的: 就像他的名字一样, 并(union)和查(find), 是要实现将两个集合快速并在一起, 以及快速从集合中查找到某两个元素是否相连的一种数据结构, 算法第四版中给出了一幅很具象的图, 即下图, 我们可以较为清楚地看到左下角有一个孤立起来的连通分量, 在图中也可以找到一个孤立的点, 这也许很轻松, 但是如果要判断某两个点是否连通, 则非常地困难, 并查集就是来解决这些问题的;
-
并查集的组成: 首先有两个基本的东西: 表示身份的数组id[], 表示当前有多少个集合的count(研究的对象的基本元素是上图的点, 在并查集的研究中, 用id[]来表示那些点); 其次就是几个方法: union(int p, int q), 负责将p和q背后的两个集合连通起来, find(int p), 负责找到p对应的代表节点, connected(int p, int q), 负责判断这两个点是否连通;
所以最终的代码如下:
public class UF { private int[] id; private int count; public UF(int N) { //并查集的初始化 id = new int[N]; count = N; for(int i = 0; i < N; i++) { id[i] = i; } } public int size() { return count; } public int find(int p) { } public boolean connected(int p, int q) { } public void union(int p, int q){ } }
而可以优化的就是那三个方法;
-
并查集版本的简述: 每一个并查集的版本的优点都展现在了他们的名字里, quick-find版本的find( )方法只需访问一次数组, quick-union版本的union( )方法也只需要访问一次数组, 加权quick-union版本对union( )方法进行了优化, 使其在合并集合时更加智能, 路径压缩使得find( )和connected( )接近常数项级别;
2. quick-find
-
算法实现: find(int p)方法只寻找到p节点的父亲节点, union(int p, int q)方法需要将那两个节点的父亲节点进行比较, 如果不同, 则把他们合并, 谁合并到谁无所谓, 比如要将p对应的集合合并到q对应的集合, 合并的方式就为遍历数组, 如果碰到节点的父亲节点为p的父亲节点, 即数组的值为id[p], 则把这个点的数组值改为id[q], 也就是改为q的父亲节点;
public static class UF { private int[] id; private int count; public UF(int N) { id = new