个人笔记,仅供复习
1.集合
1.1 集合运算:交、并、补、差,判断一个元素是否属于一个集合。
1.2 并查集:集合并、查某元素属于什么集合。
1.3 并查集问题中集合存储的实现:用树结构表示集合,树的每一个结点代表一个元素
2.对并查集的操作
2.1 查询:为了查询两个结点是否属于同一集合,我们需要沿着树向上走,来查询包含这个元素的树的根是谁。如果两个结点走到了同一个根,那么就可以知道它们属于同一组。
2.2 合并:从一个集合的根向另一个集合的根连边,这样两棵树就变成了一棵树,也就把两个集合并成一个集合了。
2.2.1 伪代码:(将X1和X2两个元素所在的集合合并)
- 分别找到到X1和X2两个元素所在集合树的根结点
- 如果它们不同根,则将其中一个根结点的父结点指针设置成另一个根结点的数组下标。
3.优化
3.1 路径压缩(合并时的优化):
- 对于每棵树,记录它的高度(Rank)
- 合并时,如果两棵树Rank不同,那么从Rank小的向Rank大的连边
3.2 路径压缩(查询时的优化):对于每个结点,一点向上走到了一次根节点,就把这个点到父节点的边改为直接向根节点连边。
3.3 代码实例:
#include<iostream>
using namespace std;
const int maxn = 100;
int par[maxn];
int Rank[maxn];//优化
void clear(int n){//初始化n个元素
for(int i = 0;i < n;i++){
par[i] = i;//一开始把每个节点看成一棵树
Rank[i] = 0;
}
}
int Find(int x){
if(par[x] == x) return x;
else par[x] = Find(par[x]);//优化
}
void unite(int x,int y){//将x和y所属集合合并
x = Find(x);
y = Find(y);
if(x == y) return;
if(Rank[x] < Rank[y]) par[x] = y;
else{
par[y] = x;
if(Rank[x] == Rank[y]) Rank[x]++;
}
}
bool same(int a,int b){//判断a和b是否属于同一集合
return Find(a) == Find(b);
}