1 查询的优化——路径压缩
在查询函数find_set(int i)中,查询元素i所属的集,需要搜索路径找到根结点,返回的结果是根结点。这条搜索路径可能很长。如果在返回的时候,顺便把i所属的集改成根结点,那么下次再搜的时候,就能在O(1)的时间内得到结果。
/*---未优化---*/
int find_set(int x){ //查找
return x==s[x]? x:find_set(s[x]);
}
/*---递归优化---*/
int find_set(int x){
if(x != s[x])
s[x] = find_set(s[x]); //路径压缩
return s[x];
}
/*---非递归优化---*/
int find_set(int x){
int r = x;
while ( s[r] != r ) r=s[r]; //找到根结点
int i = x, j;
while(i != r){
j = s[i]; //用临时变量j记录
s[i]= r ; //把路径上元素的集改为根结点
i = j;
}
return r;
}
2 合并的优化
合并元素x和y时,先搜到它们的根结点,然后再合并这两个根结点,即把一个根结点的集改成另一个根结点。这两个根结点的高度不同,如果把高度较小的集合并到较大的集上,能减少树的高度。下面是优化后的代码,在初始化时用height[i]定义元素i的高度,在合并时更改。
int height[maxn];
void init_set(){ //初始化
for(int i = 1; i <= maxn; i++){
s[i] = i;
height[i]=0; //树的高度
}
}
void merge_set(int x, int y){ //优化合并操作
x = find_set(x);
y = find_set(y);
if (height[x] == height[y]) {
height[x] = height[x] + 1; //合并,树的高度加一
s[y] = x;
}
else{ //把矮树并到高树上,高树的高度保持不变
if (height[x] < height[y]) s[x] = y; // y<--x
else s[y] = x; // x<--y
}
}