并查集(Union Find)
Posted qbits
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并查集(Union Find)相关的知识,希望对你有一定的参考价值。
特点
常用于确定无向图的连通分量(虽然DFS也可以做),求最小公共祖先(LCA)
朴素版并查集
vector<int> v;
void Union(int i, int j)
int pi = Find(i);
int pj = Find(j);
v[pi] = pj;
int Find(int i)
while(v[i] != i) i = v[i];
return i;
路径压缩
为了减少树的高度,直接将查找路径上的结点连接到根上去,降低查找时间
int Find(int i)
if(v[i] != i) v[i] = Find(v[i]);
return v[i];
按秩合并
秩表示结点高度的上界,(算法导论上说路径压缩不会改变每个结点的秩?没想通,难道是指的上界),将秩小的树指向秩大的树称为按秩合并
void Union(int i, int j)
int ri = Find(i);
int rj = Find(j);
if(ri == rj) return ;
if(Rank[ri] > Rank[rj])
v[rj] = ri;
else if(Rank[ri] < Rank[rj])
v[ri] = rj;
else
Rank[ri] += 1;
v[rj] = ri;
时间复杂度
朴素版并查集的Union操作的摊还时间为\(O(n)\)
使用按秩合并的Union操作的摊还时间为\(O(\log_2 n)\)
同时采用按秩合并和路径压缩的最坏运行时间每个操作的摊还时间为\(\alpha(n)\)(反阿克曼函数,近似为一个常数)
详细分析可以写一本书...
例题
class Solution
private:
vector<int> Rank;
vector<int> v;
void Union(int i, int j)
int ri = Find(i);
int rj = Find(j);
if(ri == rj) return ;
if(Rank[ri] > Rank[rj])
v[rj] = ri;
else if(Rank[ri] < Rank[rj])
v[ri] = rj;
else
Rank[ri] += 1;
v[rj] = ri;
int Find(int i)
if(v[i] != i) v[i] = Find(v[i]);
return v[i];
public:
int findCircleNum(vector<vector<int>>& M)
int n = M.size();
for(int i = 0; i < n; i++)
v.push_back(i);
Rank.push_back(0);
for(int i = 0; i < n; i++)
for(int j = i + 1; j < n; j++)
if(M[i][j] == 1)
Union(i, j);
int cnt = 0;
for(int i = 0; i < n; i++)
if(Find(i) == i) cnt++;
return cnt;
;
以上是关于并查集(Union Find)的主要内容,如果未能解决你的问题,请参考以下文章