1、什么是并查集
2、Quick Find
第一版并查集 Quick Find 的代码如下:
package com.lkj;
// 我们的第一版Union-Find,第一版Union-Find本质就是一个数组
public class UnionFind1 implements UF
{
//定义每个元素所属集合的编号id
private int[] id;
//初始化,用户传递进来的是并查集需要考虑的元素的个数(并查集元素个数一开始就确定,随后并查集内元素个数不变,没有添加或者删除)
public UnionFind1(int size)
{
/**
因为一开始每一个元素都属于不同的集合,只有合并后才有元素属于同一个集合,
那么我们初始化的时候,有多少个元素size,就设置多少个集合,即集合的编号有size个。
此时元素编号从 0到size-1(不变),而集合的编号初始化从 0到size-1,我们后面可以通过合并改变元素对应集合的编号。
理解:元素对应的编号,从 0到size-1,相当于数组id下标。
我们根据数组下标 i,就可以查找到下标对应元素对应的集合的id:id[i](数组内存储的是元素对应的集合编号)
*/
id = new int[size];
for (int i = 0; i < size ; i++)
{
id[i] = i;//第零个元素对应的集合编号为0,第一个元素对应的集合编号为1,...
}
}
/** 并查集考虑的元素个数(由用户设定,并查集元素个数一旦确定便不再改变)*/
@Override
public int getSize()
{
return id.length;
}
// 查找元素p所对应的集合编号,O(1)复杂度
private int find(int p)
{
/*
p指的是元素对应的编号,从 0到size-1,相当于数组下标。
通过元素编号p(数组下标)就可以找到元素对应的集合的id:id[p]
*/
if(p < 0 || p >= id.length)
throw new IllegalArgumentException("p is out of bound.");
return id[p];
}
// 查看元素p和元素q是否所属一个集合,O(1)复杂度
@Override
public boolean isConnextion(int p, int q)
{
//元素对应的集合编号相同则属于同一个集合,否则属于不同集合
return find(p) == find(q);
}
// 合并元素p和元素q所属的集合,O(n) 复杂度
@Override
public void unionElements(int p, int q)
{
//先查询出元素p,元素q所属集合的id
int pID = find(p);
int qID = find(q);
if(qID == pID)
return;//原来2歌词元素就属于同一个集合,这不需要合并
//否则,将属于pID集合的所有元素改为属于qID(转换过来也是一样的,pID与qID任意取)
for (int i = 0; i < id.length ; i++)
{
if(id[i] == pID)
id[i] = qID;
}
}
}
3、QuickUnion
这种QuickUnion才是并查集真正的实现思路。
QuickUnion的代码如下:
package com.lkj;
public class UnionFind2 implements UF
{
/**
同样,数组的下标是元素编号,数组每个下标位置对应的值即下标对应元素指向的元素,
即下标对应的元素与那一个元素是属于同一个集合
*/
private int[] parent;