并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高。
笔者采用 jvav 语言演示 并查集结构 时间复杂度O(1) (接近)
//并查集
//判断两个元素是否属于同一集合
//将两个集合连接
//要求时间复杂度O(1)
class UnionFieldSet<V> {
HashMap<V, Element> eMap;
HashMap<Element, Element> fMap;
HashMap<Element, Integer> iMap;
public UnionFieldSet(List<V> list) {
eMap = new HashMap<>();
fMap = new HashMap<>();
iMap = new HashMap<>();
for (V e : list) {
Element<V> E = new Element<>(e);
eMap.put(e, E);
fMap.put(E, E);
iMap.put(E, 1);
}
}
Element getHead(Element<V> e) {
Stack<Element<V>> stack = new Stack<>();
while (e != fMap.get(e)) {
stack.add(e);
e = fMap.get(e);
}
while (!stack.empty()) {
fMap.put(stack.pop(), e);
}
return e;
}
boolean isSame(V a, V b) {
if (!(eMap.containsKey(a) && eMap.containsKey(b))) return false;
if (getHead(eMap.get(a)) == getHead(eMap.get(b))) return true;
return false;
}
void union(V a, V b) {
if (!(eMap.containsKey(a) && eMap.containsKey(b))) return;
Element<V> ah = getHead(eMap.get(a));
Element<V> bh = getHead(eMap.get(b));
if (ah == bh) return;
Element<V> s = iMap.get(ah) < iMap.get(bh) ? ah : bh;
Element<V> l = s != eMap.get(ah) ? ah : bh;
fMap.put(s, l);
iMap.put(l, iMap.get(ah) + iMap.get(bh));
iMap.remove(s);
}
}
并查集相关接口
判断两个元素是否属于同一集合 时间复杂度O(1)
boolean isSame(V a, V b)
合并两个元素所在的集合 时间复杂度O(1)
void union(V a, V b)
获取元素e的头元素,并使集合所有元素指向头元素
Element getHead(Element<V> e)
世界线回溯,从jvav到架构师