并查集有两个优化。
首先是初始化:
int fa[maxn], r[maxn]; void init(int n) { for (int i=1; i<=n; ++i) { fa[i] = i; r[i] = 1; } }
优化:
一、按秩合并
描述:就是在对两个不同子集连接时,按照rank来连,也就是rank低的连在rank高的下面。rank高的做父亲节点。
作用,这样类似维护了一棵树,树是rank高的在上。
void unin(int u, int v) { // 非按秩合并 int fau = find_fa(u); int fav = find_fa(v); if (fau != fav) fa[fav] = fau; }
void unin(int u, int v) { // 按秩合并 int fau = find_fa(u); int fav = find_fa(v); if (fau == fav) return; if (r[u] < r[v]) fa[fau] = fav; else { if (r[u] == r[v]) r[u]++; fa[fav] = fau; } }
二、路径压缩
描述:假如fa数组已经嵌套了N层,那么传统的做法去找祖先要做N次,当N很大时,这种做法很没效率。
这是朴素查找的代码,适合数据量不大的情况:
int findx(int x) { int r=x; while(parent[r] !=r) r=parent[r]; return r; }
递归式路径压缩易RE:
int find_fa(int v) { // 递归式路径压缩 if (fa[v] != v) fa[v] = find_fa(fa[v]); return fa[v]; }
非递归式路径压缩:
int find_fa(int v) { // 非递归式路径压缩 int k, j, r; r = v; while(r != fa[r]) r = fa[r]; //找到根节点 记录在r上。 k = v; while(k != r) { j = fa[k]; fa[k] = r; k = j; } return r; }