并查集的学习记录

并查集要用到的概念和一些人性化的例子很容易查找到。

其thought core 是,要集合里的元素代表集合,可以用各成一派,各自为战来人性的表达。

所以第一步很水到渠成,设定成员函数使传入的元素自己等于自己(根节点等于自己,自己就是父节点。

同时我引入一个第一原则,就是两个树合并,树高度高的或者结点多的更适合做根节点,如果你不遵守这个原则,你的代码时间复杂度就会增加,虽然不一定change数量级,但仍不推荐这样做,所以我们先引入一个rank数组,你可以叫他秩或者等级,随便什么都可以,他是为了帮我们的编译器在合并树的时候找到性价比最高的路线,

int father[maxn],

int rank[maxn]

inline void init(int n)

{

for(int i=1;i<=n  ++i)

{

father[i]=i;

rank[i]//

}

如上是这个程序的初始化操作

接下来则要编写有关查找集合内某个元素的根节点的成员函数。

int findRootElement(int X)

{

return father[i]==x?x:findRootElement(father[x]);

}

这里是路径压缩,你可以把它近似理解成,为了下次查找方便,让查找过的元素指向根节点,这样他就从原本下面的层数一跃而到此树的第二层了,

 inline void compress(int x)

if(x==father[x])

return x;

else

father[x]=compress(father[x])

return father[x]

}

然后就是合并,这也是我前文提到的,因为考虑到合并的倾向性,这与我前文提到的rank密切相关,你可以理解他为倾向等级更specialized的说法叫秩,我们暂时把他理解成合并时寻找最优线路的一个对照物。有意思的是,我们可以选择使用其他的方法替代我刚刚所说的,比如使用结点数量来作为合并时寻找最优线路的对照物,这里我们只说前者。

想象一个集合,一开始他们各自是各自的根节点(各自为战),后来经历一番厮杀过后,有两个最大的门派诞生了,他们的小弟为了跟老大近一些,与是纷纷吧各自的信物交给老大,这也就是都指向了根节点的人性化说法更specialized的说法叫路径压缩。

那么如何

inline void merger(int i,int j)

{

int x=findRootElement[i],y=findRootElement[j];

if(rank[x]<=rank[y])

father[x]=y;

else

father[y]=x;

if(rank[x]=rank[y]&&x!=y)

rank[y]++/

到这里也就结束了,值得注意的是,合并后原来的老大也成了小弟,所以要rank的值应该加1,因为深度增加了,她不再是第一层,而是第二层,她原本的小弟依旧指向它,只不过不再是1的深度,而是2,因为曾经的老大已经是别人小弟,深度加1变为2

在启动函数里面,要善用路径压缩和树的合并,这点尤为重要。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值