并查集
正如它的名字一样,并查集(Union-Find)就是用来对集合进行 合并(Union) 与 查询(Find) 操作的一种数据结构。
合并 就是将两个不相交的集合合并成一个集合。
查询 就是查询两个元素是否属于同一集合。
并查集的原理
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题(即所谓的并、查)。比如说,我们可以用并查集来判断一个森林中有几棵树、某个节点是否属于某棵树等。
组成
并查集主要由一个整型数组pre[ ]和两个函数find( )、join( )构成。
数组 pre[ ] 记录了每个点的前驱节点是谁,函数 find(x) 用于查找指定节点 x 属于哪个集合,函数 join(x,y) 用于合并两个节点 x 和 y 。
现实意义
比如现在有这样的情况:
目前饭局有10个人,没两个人之间都可能存在远方亲戚关系,如何将个人分成不同的家庭?现在将个人编号为{0,1,2,3,4,5,6,7,8,9}
-1表示假设每个人之间都不存在亲戚关系
接下来,饭局中的人互相交谈,了解到自己的亲戚关系,因此可以形成不同的家庭。比如:当前是s1:{0,6,7,8},s2:{1,4,9},s3:{2,3,5}形成了不同的家庭。
用树模型表示
因此规定并查集数组有下面的规定:
- 数组的下标对应集合中元素的编号
- 数组中如果为负数,负号代表根,数字代表该集合中元素个数
- 数组中如果为非负数,代表该元素双亲在数组中的下标
- 如果此时0和1发现也有亲戚关系,那么s1和s2可以合并为一个新的家庭
并查集需要有下面的接口
- 查找元素属于哪个集合
- 查看两个元素是否属于一个集合
- 合并两个集合
- 集合的个数
并查集的实现
创建一个并查集
并查集底层就是一个数组,数组内每个元素初始为-1。
public class unionfindset {
public int[] elem;
public int usedSize;
public unionfindset(int n ){
this.elem = new int[n];
Arrays.fill(elem,-1);
}
public static void main(String[] args) {
unionfindset unionfindset = new unionfindset(10);
System.out.println(123);
}
}
功能实现:
/**
* 查找数据 x 的根结点
* @param x
* @return 下标
*/
public int findRoot(int x){
if (x<0){
throw new IndexOutOfBoundsException("下标不合法,是负数");
}
while (elem[x]>=0){
x = elem[x]; //1 0
}
return x;
}
/**
* 查询x1 和 x2 是不是同一个集合
* @param x1
* @param x2
* @return
*/
public boolean isSameUnionFindSet(int x1,int x2){
int index1 = findRoot(x1);
int index2 = findRoot(x2);
if (index1==index2){
return true;
}else{
return false;
}
}
/**