浅谈并查集
最近几天学习了并查集。并查集干的无非就是两件事:并和查。当然在查的时候要进行路径压缩,这个我之后会说。
首先很感谢这个例子,让我明白了并查集实质是什么。
下面就来看这个例子:
话说江湖上散落着各式各样的大侠,有上千个之多。他们没有什么正当职业,整天背着剑在外面走来走去,碰到和自己不是一路人的,就免不了要打一架。但 大侠们有一个优点就是讲义气,绝对不打自己的朋友。而且他们信奉“朋友的朋友就是我的朋友”,只要是能通过朋友关系串联起来的,不管拐了多少个弯,都认为 是自己人。这样一来,江湖上就形成了一个一个的群落,通过两两之间的朋友关系串联起来。而不在同一个群落的人,无论如何都无法通过朋友关系连起来,于是就 可以放心往死了打。但是两个原本互不相识的人,如何判断是否属于一个朋友圈呢?我们可以在每个朋友圈内推举出一个比较有名望的人,作为该圈子的代表人物, 这样,每个圈子就可以这样命名“齐达内朋友之队”“罗纳尔多朋友之队”……两人只要互相对一下自己的队长是不是同一个人,就可以确定敌友关系了。
但是还有问题啊,大侠们只知道自己直接的朋友是谁,很多人压根就不认识队长,要判断自己的队长是谁,只能漫无目的的通过朋友的朋友关系问下去:“你是不是
队长?你是不是队长?”这样一来,队长面子上挂不住了,而且效率太低,还有可能陷入无限循环中。于是队长下令,重新组队。队内所有人实行分等级制度,形成
树状结构,我队长就是根节点,下面分别是二级队员、三级队员。每个人只要记住自己的上级是谁就行了。遇到判断敌友的时候,只要一层层向上问,直到最高层,
就可以在短时间内确定队长是谁了。由于我们关心的只是两个人之间是否连通,至于他们是如何连通的,以及每个圈子内部的结构是怎样的,甚至队长是谁,并不重
要。所以我们可以放任队长随意重新组队,只要不搞错敌友关系就好了。于是,门派产生了。
好的,现在已经搞清楚并查集是什么了,那么要怎么具体实现呢?
先说查吧:
1 int find (int a){ 2 if(father[a]!=a){ 3 father[a]=find(father[a]); //一直递归直到找到根节点 4 } 5 return a; 6 }
接下来是并:
1 int link (int a ,int b){ 2 int x=find(a);//找到a的根节点 3 int y=find(b);//找到b的根节点 4 if(x!=y) //a,b的根节点不是同一个 5 father[y]=x; //把b的根节点连接到a上 6 7 }