并查集是一类抽象度较高的数据结构。
并查集主要用于处理一些相交,相连,相关的合并的这类问题。
使用并查集时,我们一般会遇到某些点相交相连,某些又不相连,但是通过彼此相连能组成一个或多个集合的问题,比如A与B相交,B与C相交,在并查集中,我们就能判断出A与C 是相交的。因为并查集具有连通性,A与C会通过B这个中间人而认识,所以A与C也是相交的。
并查集还有一个特点就是A与B是相交的那么B与A也一定是相交的,这就是并查集的双向性,不会出现A自认为与B是朋友和B不这么认为的情况。由此看来计算机语言比人类关系简单的多了。
假设平面上有N个点,通过若干次的链接。判断哪些点是连在一起的。维护这种连通关系和查询这种连通关系,就称之为并查集。
连通性:
- 传递性:(a→b,b→c)⇒a→c
- 双向性
建立并查集需要三个步骤:
-
建立一个元素集合,用来存放并查集
fa = new Array(n + 1) for (let i = 0; i < n; i++) { fa[i] = i }
这里我们新建了一个长度为N+1的数组集合,并将每个值都赋值为其下标,这里目的是每个元素都是独立的,都有自己的属性
-
查询元素
get(x) { return fa[x] = (fa[x] == x ? x : get(fa[x])) }
这里我们传入需要查找的元素,我们假定如果有两个元素的相连的,那么我们将其中一个元素定为一个根元素,而另一个元素则为其的子结点,他们生长在一棵树上,他们拥有同一个根,我们将这类元素都用统一的属性表示,也就是说他们在数组中拥有相同的值,而这个值就是所查找到的第一个元素的值也就是这个树的根。
如果查找到该元素的值就是自己的下标,那么这个元素就是他所在树的根,如果不是就继续向上查找,直至找到这个根。如果多个元素拥有同一个根,则证明这些元素是连通的。
-
连通元素
merge(a, b) { fa[get(a)] = get(b) }
如果确定a 和b是连通的,那么就将一个元素的属性赋值到另一个元素,使其拥有同一个祖先,也就是建立到一棵树下面。
最后总结代码结构
class UnionSet {
constructor(n) {
this.fa = new Array(n + 1)
this.n = n
for (let i = 0; i < n; i++) {
this.fa[i] = i
}
}
get(x) {
return this.fa[x] = (this.fa[x] == x ? x : this.get(this.fa[x]))
}
merge(a, b) {
this.fa[this.get(a)] = this.get(b)
}
}