并查集
程序员文章站
2022-06-23 12:51:22
...
并查集:并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。也就是说在合并的时候不需要考虑两个集合之间的元素是否会重合。
并查集顾名思义:并与查
并者:合并两个集合
查者:查找元素在哪个集合中
每个集合有一个根(root),root的id也就是集合的id。当查找一个元素的时候其实返回的是root的id。
Disjoint-set/Union-find Forest
Find(x): find the root/cluster-id of x
查找x的根结点
Union(x, y): merge two clusters
合并x, y所在的集合
在O(1)*时间内查询2个元素是否在同一个集合里面
Find: O(ɑ(n))* ≈ O(1)
Union: O(ɑ(n))* ≈ O(1)
Space: O(n)
空间复杂度: O(n)
时间复杂度: Find O(n) 未优化的情况。
2个关键优化
路径压缩,把树压扁
按秩排序。把秩小的树合并到秩大的树下面
public class UnionFind {
private int[] parent;
private int[] weight;
private int size;
public UnionFind(int size) {
this.parent = new int[size];
this.weight = new int[size];
this.size = size;
for (int i = 0; i < size; i++) {
this.parent[i] = i;//每个结点的代表结点就是自己
this.weight[i] = 1;//每个代表结点都只有自己一个子节点
}
}
public int find(int element) {
while (element != parent[element]) {
parent[element] = parent[parent[element]];//压缩高度
element = parent[element];
}
return element;
}
public boolean isConnected(int firstElement, int secondElement) {
return find(firstElement) == find(secondElement);
}
public void unionElements(int firstElement, int secondElement) {
int firstRoot = find(firstElement);
int secondRoot = find(secondElement);
//如果已经属于同一个集合了,就不用再合并了。
if (firstRoot == secondRoot) {
return;
}
//谁的子节点多久合并到它的下面
if (weight[firstRoot] > weight[secondRoot]) {
parent[secondRoot] = firstRoot;
weight[firstRoot] += weight[secondRoot];
} else {
parent[firstRoot] = secondRoot;
weight[secondRoot] += weight[firstRoot];
}
}
private void printArr(int[] arr){
for(int p : arr){
System.out.print(p+"\t");
}
System.out.println();
}
public static void main(String[] args) {
int n = 10;
UnionFind union = new UnionFind(n);
System.out.println("初始parent:");
union.printArr(union.parent);
System.out.println("初始weight:");
union.printArr(union.weight);
System.out.println("连接了5 6 之后的parent:");
union.unionElements(5, 6);
union.printArr(union.parent);
System.out.println("连接了5 6 之后的weight:");
union.printArr(union.weight);
System.out.println("连接了1 2 之后的parent:");
union.unionElements(1, 2);
union.printArr(union.parent);
System.out.println("连接了1 2 之后的weight:");
union.printArr(union.weight);
System.out.println("连接了2 3 之后的parent:");
union.unionElements(2, 3);
union.printArr(union.parent);
System.out.println("连接了2 3 之后的weight:");
union.printArr(union.weight);
System.out.println("连接了1 4 之后的parent:");
union.unionElements(1, 4);
union.printArr(union.parent);
System.out.println("连接了1 4 之后的weight:");
union.printArr(union.weight);
System.out.println("连接了1 5 之后的parent:");
union.unionElements(1, 5);
union.printArr(union.parent);
System.out.println("连接了1 5 之后的weight:");
union.printArr(union.weight);
System.out.println("1 6 是否连接:" + union.isConnected(1, 6));
System.out.println("1 8 是否连接:" + union.isConnected(1, 8));
}
}
- LeetCode 399. Evaluate Division
- LeetCode 547. Friend Circles
- LeetCode 684. Redundant Connection
- LeetCode 685. Redundant Connection II
- LeetCode 839. Similar String Groups
上一篇: 并查集