并查集,这是个比较简单的东西,用森林模拟集合,集合合并则是两颗树的合并,查找集合则是寻找某棵树的根节点
因为不可避免的会遇到各种合并操作,,所以可能导致某棵树的深度较大,,对应的则出现了并查集的路径压缩还有启发式合并
这里不将路径压缩,主要是这个东西比较普及了,而且理解起来不难。
所以直接进入正题:启发式合并
第一次看到这个名称,实在刘汝佳的书上,当时还惊讶,并查集写了一年了,还真不知道这个启发式合并,接着看,发现实现是使用了一个rank数组,,,原书这么说的:
然后就懵了,秩这个东西怎么理解……
于是上网寻找,发现很多blog所描述的都和书上几乎一模一样。。
所以自己想办法理解,,还好理解了
这里举个例子
假设我们把这些树看成——一个个城市,而这些城市,因发展的程度被分为不同等级,比如小型城市,中型城市,大型城市,城市与城市之间可以合并,并且规定,小型城市和小型城市合并,其中一个城市会升级为中型城市,两个中型城市合并,其中一个城市会升级为高级城市
我们再次做一个更严密的规则:
回到树——这个问题
我们假设rank[a]表示树a的等级,姑且这么称呼吧,叫做名称也可以。根据上面的规则(转换一下),如果一棵树的等级较高,则这棵树的”规模“会比较高,也就是深度会深一些,根据之前的合并优化规则:
一个优化是:把小的树合并到大树中,这样会让深度不太大。
也就是把等级较低的树合并到等级较高的树上
我们写一个合并函数,这个函数需要根据两棵树的等级(rank)来判断哪棵树合并到另一棵树,并且判断一棵树是否需要升级
代码:
void union_ (int a,int b) {
int x = find_(a), y = find_(b);
if (ranks[x] > ranks[y]) {//两棵树一定不同级,不存在升级操作
bcset[y] = x;
} else {
bcset[x] = y;
if (ranks[x] == ranks[y]) {//两棵同等级的树合并,其中一棵树升级
ranks[y] ++;
}
}
}
因篇幅问题不能全部显示,请点此查看更多更全内容