并查集(Union-Find)粗略介绍

来源:互联网 发布:阿里云邮如何改密码 编辑:程序博客网 时间:2024/04/27 14:54

并查集:一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。

:就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。

例子:为了解释并查集的原理,我将举一个经常用来解释并查集的一个例子。话说江湖上散落着各式各样的大侠,有上千个之多。他们没有什么正当职业,整天背着剑在外面走来走去,碰到和自己不是一路人的,就免不了要打一架。但大侠们有一个优点就是讲义气,绝对不打自己的朋友。而且他们信奉“朋友的朋友就是我的朋友”,只要是能通过朋友关系串联起来的,不管拐了多少个弯,都认为是自己人。这样一来,江湖上就形成了一个一个的群落,通过两两之间的朋友关系串联起来。而不在同一个群落的人,无论如何都无法通过朋友关系连起来,于是就可以放心往死了打。但是两个原本互不相识的人,如何判断是否属于一个朋友圈呢?我们可以在每个朋友圈内推举出一个比较有名望的人,作为该圈子的代表人物,这样,每个圈子就可以这样命名“齐达内朋友之队”“罗纳尔多朋友之队”……两人只要互相对一下自己的队长是不是同一个人,就可以确定敌友关系了。

但是还有问题啊,大侠们只知道自己直接的朋友是谁,很多人压根就不认识队长,要判断自己的队长是谁,只能漫无目的的通过朋友的朋友关系问下去:“你是不是队长?你是不是队长?”这样一来,队长面子上挂不住了,而且效率太低,还有可能陷入无限循环中。于是队长下令,重新组队。队内所有人实行分等级制度,形成树状结构,我队长就是根节点,下面分别是二级队员、三级队员。每个人只要记住自己的上级是谁就行了(当然可以直接记成当前门派最高的上级这就是状态压缩的思想)。遇到判断敌友的时候,只要一层层向上问,直到最高层,就可以在短时间内确定队长是谁了。由于我们关心的只是两个人之间是否连通,至于他们是如何连通的,以及每个圈子内部的结构是怎样的,甚至队长是谁,并不重要。所以我们可以放任队长随意重新组队,只要不搞错敌友关系就好了。于是,门派产生了。如下图所示

这里写图片描述

那下面我们就来实现一下并查集, int p[1000],这个数组来拿记录每个大侠的上级是哪个。比如p[2]=1,2的上级就是1。而p[1]=1,自己的上级是自己,说明自己就是这个门派的掌门人了。

首先我们肯定要初始化这个数组 每个人为不同的派(即每个人所在门派初始化为其自身) 所以代码如下

void init(){      for(int i=0;i<=n;i++)//一共有n个人            p[i]=i;}

当给出了两个人x,y之间为同一派别时,首先用判断他们两个人的最高上级是否是同一个人,如果不是就合并他们

void UnionSet(int x,int y){   int xx=Find(x);//Find函数为查找x的最高上级是哪个 状态压缩   int yy=Find(y);//查找y的最高上级是哪个 状态压缩   if(xx!=yy)//判断是否是一个门派(门派最高层是否相同)   {    p[yy]=xx;   }}

下来我们就来说说Find函数 查找对应的最高上级是哪个 我们可以用宋青书这条线来当例子 张三丰为1 宋远桥为2 宋青书为3 初始化三个为各自的门派 因为他们是一个门派 所以要合并他们 合并的时候要判断他们是否是在一个集合内 合并宋远桥和宋青书时 因为xx=Find(2)=2 yy=Find(3)=3 两者不再一个集合内 合并标记p数组 p[3]=2 宋青书指向他老爸宋远桥 宋青书和宋远桥的线就连接到了一起 好 接下来又判断张三丰和宋远桥是否在同一个集合中 xx=Find(1)=1 yy=Find(2) 因为张三丰和宋远桥不再一个门派内,就可以合并两者 此时p[2]=1 宋远桥就指向了张三丰 宋远桥和张三丰的关系线也连接到了一起 这样宋青书和张三丰也是连接到一起的了 下面如果我们要继续让我们合并张三丰和宋青书,那就会出现一些问题了。因为xx=Find(1)=1 yy=Find(3) 因为宋青书的最高上级不是自己 就要查他老爸的最高上级 他老爸的最高上级也不是自己 就查他老爸的最高上级 一查就查到了张三丰 没错 这样yy=Find(3)=1 宋青书他的最高上级就是张三丰 因为xx=yy 所以两者就在一个门派内 无法合并

int Find(int x){   if(x!=p[x])//说明他的最高上级不是自己   {       p[x]=Find(p[x]);   }   return p[x];}

所以总结起来并查集的重点就只有三步:

初始化

把每个点所在集合初始化为其自身。
通常来说,这个步骤在每次使用该数据结构时只需要执行一次,无论何种实现方式,时间复杂度均为O(N)。

查找

查找元素所在的集合,即根节点。

合并

将两个元素所在的集合合并为一个集合。
通常来说,合并之前,应先判断两个元素是否属于同一集合,这可用上面的“查找”操作实现。

END!!!!!!!!!!!!!!!!!!

1 0
原创粉丝点击