并查集
public class UnionFind_QU_R_PC {
int[] parents;
int[] rank;
public UnionFind_QU_R_PC(int capacity) {
parents=new int[capacity];
for (int i = 0; i < parents.length; i++) {
parents[i]=i;
}
rank=new int[capacity];
for (int i = 0; i < rank.length; i++) {
rank[i]=1;
}
}
/**
* rank优化 rank为高度
* @param v1
* @param v2
*/
public void union(int v1,int v2) {
int p1=find(v1);
int p2=find(v2);
if(rank[p1]<rank[p2]) {
parents[p1]=p2;
}else if(rank[p1] > rank[p2]){
parents[p2] = p1;
}else{ // rank[p1] == rank[p2]
parents[p1] = p2;
rank[p2] += 1;
}
}
/** 在 find 时使路径上的所有节点都指向根节点,从而降低树的高度。
* 路径压缩
* @param v
* @return
*/
// public int find(int v) {
// check(v);
// if(parents[v]!=v) {
// parents[v]=find(parents[v]);
// }
// return parents[v];
// }
/** 使路径上的每个节点都指向其祖父节点
* 路径分裂
* @param v
* @return
*/
// public int find(int v) {
// check(v);
// while(parents[v]!=v) {
// int p=parents[v];
// parents[v]=parents[parents[v]];
// v=p;
// }
// return parents[v];
// }
/** 使路径上每隔一个节点就指向其祖父节点
* 路径减半
* @param v
* @return
*/
public int find(int v){
check(v);
while(v != parents[v]){
parents[v] = parents[parents[v]];
v = parents[v];
}
return parents[v];
}
/**
* 检查是否合法
* @param v
*/
public void check(int v) {
if(v<0||v>parents.length) {
throw new IllegalArgumentException("数组越界!");
}
}
public static void main(String[] args) {
UnionFind_QU_R_PC unionFind_QU_R_PC = new UnionFind_QU_R_PC(5);
unionFind_QU_R_PC.union(0, 1);
System.out.println(unionFind_QU_R_PC.find(0));
unionFind_QU_R_PC.union(1, 2);
System.out.println(unionFind_QU_R_PC.find(2));
unionFind_QU_R_PC.union(2, 3);
System.out.println(unionFind_QU_R_PC.find(3));
}
}
通用并查集
public class UnionFind<V> {
//用 HashMap保存结点
Map<V, Node<V>> nodes=new HashMap<>();
/**
* 创建集合
* @param v
*/
public void makeSet(V v) {
if (nodes.containsKey(v)) return;
nodes.put(v, new Node<>(v));
}
/**
*
* @author 李海涛
*
* @param <V> 结点上的值 可能为数字或者字符串
*/
public static class Node<V>{
V value;
Node<V> parent=this;
int rank=1;
public Node(V value) {
this.value = value;
}
}
/**
* 找出v所在结点的根结点
* @param v
* @return
*/
public Node<V> findNode(V v){
Node<V> node = nodes.get(v);
if(node==null) return null;
while(!Objects.equals(node.value, node.parent.value)) {
node.parent=node.parent.parent;
node=node.parent;
}
return node;
}
/**
* 找到v所在结点根结点的v值
* @param v
* @return
*/
public V find(V v) {
Node<V> node = findNode(v);
return node==null ? null:node.value;
}
/**
* 将v1 v2所在的树连接起来 变成一棵树
* @param v1
* @param v2
*/
public void union(V v1,V v2) {
Node<V> p1 = findNode(v1);
Node<V> p2 = findNode(v2);
if(p1==null||p2==null) return;
if(Objects.equals(p1.value, p2.value)) return;
if(p1.rank<p2.rank) p1.parent=p2;
else if(p1.rank>p2.rank) p2.parent=p1;
else {
p1.parent=p2;
p2.rank+=1;
}
}
/**
* 判断v1所在的结点和v2所在的结点是否在同一棵树上
* @param v1
* @param v2
* @return
*/
public boolean isSame(V v1,V v2) {
return Objects.equals(find(v1),find(v2));
}
}