1.Union: 查看两个元素之间是否可连接
- 判断网络中节点连接问题
-
2.并查集的实现:
并查集中并不保存实际元素,而是元素与索引进行一一映射
// UF 接口public interface UF {int getSize();// 查看两个元素可连接boolean isConnected(int p, int q);void unionElements(int p, int q);}
// 并查集使用 Tree 实现public class UnionFind implements UF{// index 对应元素,存储的值为集合的idprivate int[] id;// 先初始化传入的并查集大小,之后的再说public UnionFind(int[] arr){id = new int[arr.length];for(int i = 0; i < arr.length; i++){id[i] = i;}}// 获取size@Overridepublic int getSize(){return id.length;}// 查看索引对应的集合public int find(int index){if (index < 0 || index > id.length) {throw new IllegalArgumentException("out of index");}return id[index];}// 查看两个元素可连接@Overridepublic boolean isConnected(int p, int q){return find(p) == find(q);}@Override// 修改其中一个节点的ID// 之后需要将所有均改为同一IDpublic void unionElements(int p, int q){int pID = find(p);int qID = find(p);if(qId == pID){return;}for(int i = 0; i < id.length(); i++){if(find[i] == qID){find[i] = pID;}}}}
// 这时候 isConnected() 的时间复杂度为O(1)
// 而 unionElement() 为 O(n)3.优化
引入父节点,这样每次就只需要修改父节点对应的上一级 节点
// 注意此时 root 节点对应的上一个父节点就是他本身public class UnionFind implements UF{// 存储 索引对应的父节点private int[] parent;// 先初始化传入的并查集大小,之后的再说public UnionFind(int[] arr){parent = new int[arr.length];for(int i = 0; i < arr.length; i++){parent[i] = i;}}// 获取size@Overridepublic int getSize(){return parent.length;}// 查看索引对应的集合public int find(int index){if (index < 0 || index > id.length) {throw new IllegalArgumentException("out of index");}// 要找到 root ,返回 所属的 root 对应的结合ID// root 节点的值与自身索引相同while(index != parent[index]){index = parent[index];}return index;}// 查看两个元素可连接@Overridepublic boolean isConnected(int p, int q){return find(p) == find(q);}@Override// 修改其中一个节点的ID// 之后需要将所有均改为同一IDpublic void unionElements(int p, int q){// 获取父节点int pParent = find(p);int qParent = find(q);// 如果两节点相同if(pParent == qParent){return;}else{// 其中一个元素的父亲节点变指向另一个元素parent[p] = qParent;}}}
// 此时 find() 的 时间复杂度为 O(h)
// unionElements() 的时间复杂度为 O(h)使用 size() 进行优化
由于时间复杂度与树的高度有关,所以size() 最好
// 注意此时 root 节点对应的上一个父节点就是他本身public class UnionFind implements UF{// 存储 索引对应的父节点private int[] parent;private int[] sz;// 先初始化传入的并查集大小,之后的再说public UnionFind(int[] arr){parent = new int[arr.length];for(int i = 0; i < arr.length; i++){parent[i] = i;sz[i] = 1;}}// 获取size@Overridepublic int getSize(){return parent.length;}// 查看索引对应的集合public int find(int index){if (index < 0 || index > id.length) {throw new IllegalArgumentException("out of index");}// 要找到 root ,返回 所属的 root 对应的结合ID// root 节点的值与自身索引相同while(index != parent[index]){index = parent[index];}return index;}// 查看两个元素可连接@Overridepublic boolean isConnected(int p, int q){return find(p) == find(q);}@Override// 修改其中一个节点的ID// 之后需要将所有均改为同一IDpublic void unionElements(int p, int q){// 获取父节点int pParent = find(p);int qParent = find(q);// 如果两节点相同if(pParent == qParent){return;}else{if(sz[qParent] > sz[pParent]){sz[qParent] += sz[pParent];parent[pParent] = qParent;}else{sz[pParent] += sz[qParent];parent[qParent] = pParent;}}}}
使用 rank()树的高度优化
blic class UnionFind implements UF{// 存储 索引对应的父节点private int[] parent;private int[] rank;// 先初始化传入的并查集大小,之后的再说public UnionFind(int[] arr){parent = new int[arr.length];rank = new int[arr.length];for(int i = 0; i < arr.length; i++){parent[i] = i;rank[i] = 1;}}// 获取size@Overridepublic int getSize(){return parent.length;}// 查看索引对应的集合public int find(int index){if (index < 0 || index > id.length) {throw new IllegalArgumentException("out of index");}// 要找到 root ,返回 所属的 root 对应的结合ID// root 节点的值与自身索引相同while(index != parent[index]){index = parent[index];}return index;}// 查看两个元素可连接@Overridepublic boolean isConnected(int p, int q){return find(p) == find(q);}@Override// 修改其中一个节点的ID// 之后需要将所有均改为同一IDpublic void unionElements(int p, int q){// 获取父节点int pParent = find(p);int qParent = find(q);// 如果两节点相同if(pParent == qParent){return;}else{if(rank[qParent] > rank[pParent]){parent[pParent] = qParent;}else if(rank[qParent] < rank[pParent]){parent[qParent] = pParent;}else{parent[pRoot] = qRoot;rank[qRoot] +=1;}}}}
直接让 索引的上移节点指向 root 节点,减少高度 , 进行路径压缩
- 让同一高度下,子节点数较多


// 在查找过程中进行的优化
public int find(int index){
if (index < 0 || index > id.length) {
throw new IllegalArgumentException("out of index");
}
// 要找到 root ,返回 所属的 root 对应的结合ID
// root 节点的值与自身索引相同
while(index != parent[index]){
parent[index] = parent[parent[index]];
index = parent[index];
}
return index;
}
