并查集算法学习(转)

转载 2016年08月30日 19:11:43

我读的博客地址是这个:

http://blog.csdn.net/dellaserss/article/details/7724401/

但是忍不住自己再写一遍顺便加入一些自己的思考。
这是我见过的最好的并查集教程,作者不知道是谁,但是读一遍,基本上并查集这个概念,以及如何快速写出代码来,基本没有问题了!


并查集是一种用来管理元素分组情况的数据结构。
并查集的结构:
每个组对应一棵树。每个元素对应一个结点。
而树的形状,结点之间谁是父亲等都不重要。

并查集是维护属于同一组的数据结构。

构成

并查集由一个整数型的数组和两个函数构成。
数组pre[ ]记录了每个点的前导点事什么,函数find是查找,join是合并。

int pre[1000];//记录每个点的前导点是什么
int find(int x) //查找根节点
{
    int r = x;
    while(pre[r] != r) //返回根节点r
        r = pre[r];

    int i = x,j;//路径压缩
    while(i != r)
    {
        j = pre[i];
        pre[i] = r;
        i = j;
    }
    return r;
}
void join(int x, int y)
{
    //判断x,y是否连通,如果连通就啥也不做,否则就把这个两个分支合并起来
    int fx = find(x);
    int fy = find(y);
    if(fx != fy)
        pre[fx] = fy;
}

以上是官面儿的解释,下面是重点。

解释find函数,这个过程实在太欢乐了。

话说江湖上散落着各式各样的大侠,有上千个之多。他们没有什么正当职业,整天背着剑在外面走来走去,碰到和自己不是一路人的,就免不了要打一架。但大侠们有一个优点就是讲义气,绝对不打自己的朋友。而且他们信奉“朋友的朋友就是我的朋友”,只要是能通过朋友关系串联起来的,不管拐了多少个弯,都认为是自己人。这样一来,江湖上就形成了一个一个的群落,通过两两之间的朋友关系串联起来。而不在同一个群落的人,无论如何都无法通过朋友关系连起来,于是就可以放心往死了打。但是两个原本互不相识的人,如何判断是否属于一个朋友圈呢?

我们可以在每个朋友圈内推举出一个比较有名望的人,作为该圈子的代表人物,这样,每个圈子就可以这样命名“齐达内朋友之队”“罗纳尔多朋友之队”……两人只要互相对一下自己的队长是不是同一个人,就可以确定敌友关系了。

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

门派

int pre[1000]数组记录了每个大侠的上级,大侠们从1或0开始编号,pre[15] = 3就表示15号大侠的上级是3号大侠。如果一个人的上级就是他自己,说明他就是掌门人了,查询到此为止。也有孤家寡人自成一派的。每个人只认识自己的上级,要想知道掌门是谁,只能一级一级查上去,find函数就是找掌门人用的

int find(int x) //查找掌门人
{
    int r = x; //委托r去找掌门
    while(pre[r] != r) //如果r的上级不是r自己
        r = pre[r]; //r就接着找他的上级,直到找到掌门为止
    return r; //掌门来了
}

join函数的含义也很有趣:

join函数,就是在两个点之间连一条线,这样一来,原先它们所在的两个板块的所有点就都可以互通了。这在图上很好办,画条线就行了。但我们现在是用并查集来描述武林中的状况的,一共只有一个pre[]数组,该如何实现呢? 还是举江湖的例子,假设现在武林中的形势如图所示。虚竹小和尚与周芷若MM是我非常喜欢的两个人物,他们的终极boss分别是玄慈方丈和灭绝师太,那明显就是两个阵营了。我不希望他们互相打架,就对他俩说:“你们两位拉拉勾,做好朋友吧。”他们看在我的面子上,同意了。这一同意可非同小可,整个少林和峨眉派的人就不能打架了。这么重大的变化,可如何实现呀,要改动多少地方?其实非常简单,我对玄慈方丈说:“大师,麻烦你把你的上级改为灭绝师太吧。这样一来,两派原先的所有人员的终极boss都是师太,那还打个球啊!反正我们关心的只是连通性,门派内部的结构不要紧的。”玄慈一听肯定火大了:“我靠,凭什么是我变成她手下呀,怎么不反过来?我抗议!”抗议无效,上天安排的,最大。反正谁加入谁效果是一样的,我就随手指定了一个。这段函数的意思很明白了吧?

void join(int x, int y) //我想让虚竹和周芷若做朋友
{
    int fx = find(x); //虚竹的老大是玄慈
    int fy = find(y); //芷若mm的老大是灭绝
    if(fx != fy) //玄慈和方丈不是同一个人
        pre[fx] = fy; //委屈方丈当了师太的手下
}

考察路径压缩算法:

int find(int x) //查找x的掌门人
{
    int r = x; //委托r去找掌门
    while(pre[r] != r) //如果r的上级不是r自己
        r = pre[r]; //r就接着找他的上级,直到找到掌门为止

    //路径压缩:想把x和x的上级,x的上上级直到掌门的首座全都变成掌门的直系弟子
    int i = x,j; //i初始代指x
    while(i != r) //如果i不是掌门
    {
        j = pre[i]; //找到i的上级,并赋值给j
        pre[i] = r;//i的老大现在改为掌门人
        i = j;//再往上搞j,i曾经的老大,直到搞到掌门人自己为止
    }
    return r; //掌门来了
}

路径压缩

并查集算法介绍

我们在一些应用当中,经常会遇到将n个不同的元素分成一组不相交的集合,例如某省调查城镇交通状况,得到现有城镇道路统计表,当我们知道每条道路直接连通的城镇时,问最少还需要建设多少条道路才能使全省任何两个城...
  • qianchenglenger
  • qianchenglenger
  • 2015年08月09日 18:57
  • 2793

史上最浅显易懂的并查集算法

并查集是我暑假从高手那里学到的一招,觉得真是太精妙的设计了。以前我无法解决的一类问题竟然可以用如此简单高效的方法搞定。不分享出来真是对不起party了。(party:我靠,关我嘛事啊?我跟你很熟么?)...
  • u011487593
  • u011487593
  • 2015年09月17日 19:48
  • 745

小谈并查集及其算法实现

并查集   一、算法介绍: 并查集(Union-find Sets)是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题。   并查集的基本操作有两个: 1:合并 union(x, ...
  • hpuhjh
  • hpuhjh
  • 2015年08月21日 14:49
  • 2565

并查集—解密犯罪团伙

警察想查清楚有几个犯罪团伙,搜集到了一些线索: 现在有10个强盗; 1号强盗与2号强盗是同伙; 3号强盗与4号强盗是同伙; 5号强盗与2号强盗是同伙; 4号强盗与6号强盗是同伙; 2号强盗...
  • wtyvhreal
  • wtyvhreal
  • 2015年02月04日 21:39
  • 2534

并查集入门基础

 最近写了一个多星期的并查集,一瞬间贴出这么多解题报告,我想关于并查集的应用先告一段落吧,先总结一下。 在网上看到一篇关于并查集比较好的教程(姑且允许我这么说吧),不转过来是在可惜。献给爱...
  • wikioi_bai
  • wikioi_bai
  • 2014年10月05日 12:20
  • 710

数据结构学习 并查集讲解(思路,时间复杂度)

1、  概述 并查集(Disjoint set或者Union-find set)是一种树型的数据结构,常用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。 2、  基本操作 ...
  • chen_lin111
  • chen_lin111
  • 2015年12月26日 14:16
  • 3068

c++ 并查集

POWERED BY PHANTOM_LSH 大神勿喷。在编程和算法设计的时候,我们经常会遇到一些保存集合的情况,例如使用Kruskal算法求最小生成树的时候。我们只关心一些元素是否在一个集合里而不...
  • a1323933782
  • a1323933782
  • 2016年12月11日 18:40
  • 1002

Kruskal算法(贪心+并查集=最小生成树)

http://www.51nod.com/ Kruskal算法的高效实现需要一种称作并查集的结构。我们在这里不介绍并查集,只介绍Kruskal算法的基本思想和证明,实现留在以后讨论。 Krusk...
  • liangzhaoyang1
  • liangzhaoyang1
  • 2016年04月16日 17:34
  • 7447

【算法】并查集的运用

并查集的概念 朋友圈 团伙问题 连通图 总结并查集的概念并查集顾名思义就是合并和查找,问题在于合并什么,查找什么。这里有一种朴素的思想来解释这两个问题。就是把这个想成一棵树。合并什么?就是把不在这棵树...
  • gesanghuazgy
  • gesanghuazgy
  • 2016年08月10日 20:18
  • 980

带权值的并查集

题目链接:【POJ 1182】 好题! 父节点跟子节点之间一共有三种关系,父节点吃子节点,子节点吃父节点,父节点跟子节点是同类,所以用三进制表示 fa[B]=A,rank[B]=0表示与父节点是同类,...
  • YHYYXT
  • YHYYXT
  • 2016年03月08日 21:04
  • 932
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:并查集算法学习(转)
举报原因:
原因补充:

(最多只允许输入30个字)