并查集

找网上的面经的时候,看到的一个题目:
阿里旺旺里人和人之间交流产生了很多个商业群,找出一共有多少个不同的群。
给出的答案是并查集。才疏学浅,不知道并查集是什么。。
以下给出一个并查集的列子,可能就会比较好理解:

初始状态,每个元素为单调一个集合;
(2,4) -> {2,4}
(5,7) -> {2,4} {5,7}
(1,3) -> {1,3} {2,4} {5,7}
(8,9) -> {1,3} {2,4} {5,7} {8,9}
(1,2) -> {1,2,3,4} {5,7} {8,9}
(5,6) -> {1,2,3,4} {5,6,7} {8,9}
(2,3) -> {1,2,3,4} {5,6,7} {8,9}

最后我们得到3个集合{1,2,3,4}, {5,6,7}, {8,9},于是判断两个人是否有关,就变成判断两个数是否在同一个集合中的问题。如此一来,需要的数据结构就没有图结构那样庞大了。

算法的几个子过程:
(1) 开始时,为每个人建立一个集合SUB-Make-Set(x);
(2) 得到一个关系后a,b,合并相应集合SUB-Union(a,b);
(3) 此外我们还需要判断两个人是否在同一个集合中,这就涉及到如何标识集合的问题。我们可以在每个集合中选一个代表标识集合,因此我们需要一个子过程给出每个集合的代表元SUB-Find-Set(a)。于是判断两个人是否在同一个集合中,即两个人是否为亲戚,等价于判断SUB-Find-Set(a)=SUB-Find-Set(b)。

优化方法为路径压缩,此时的算法复杂度为O(1) (平均)
每次查找的时候,如果路径较长,则修改信息,以便下次查找的时候速度更快。
实现:

  • 第一步,找到根结点。
  • 第二步,修改查找路径上的所有节点,将它们都指向根结点。
find3(x)
{
r = x; while (set[r] <> r) //循环结束,则找到根节点
r = set[r];
i = x;
while (i <> r) //本循环修改查找路径中所有节点
{
j = set[i];
set[i] = r;
i = j;
} }

CSDN:http://www.cnblogs.com/cyjb/p/UnionFindSets.html
这个说的也蛮清楚的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值