【经典数据结构】并查集

等价关系与等价类

  若对于每一对元素(a,b),a,b∈S,a R b或者为true或者为false,则称在集合S上定义关系R。如果a R b为true,那么我们说a与b有关系。

  等价关系(equivalence relation)是满足下列三个性质的关系R:

  (1) 自反性:对于所有a∈S,a R a

  (2) 对称性:若a R b当且仅当b R a

  (3) 传递性:若a R b且b R c 则a R c

  关系“≤”不是等价关系。虽然它是自反的(即a≤a)、可传递的(即由a≤b和b≤c得出a≤c),但它不是对称的,因为a≤b不能得出b≤a。

  如果两个城市位于同一个国家,那么定义它们是由关系的。容易验证这是一个等价关系。如果能够通过公路从a旅行到b,则设a与b有关系。如果所有的道路都是双向行驶的,那么这种关系也是一个等价关系。

并查集: 

  在计算机科学中,并查集是一种树形的数据结构,其保持着用于处理一些不想交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示,进行快速规整。

  并查集保持一组不想交的动态集合S={S1,S2,...,Sk}。每个集合通过一个代表来识别,代表即集合中的某个成员。在某些应用中,哪一个成员被选作代表无所谓。在一些应用中,如何选择代表可能存在预先说明的规则,例如选择集合中的最小元素。

  并查集提供一下操作:

  1. Find:确定元素属于哪一个集合。它可以被用来确定两个元素是否属于同一子集。返回的是包含给定元素的集合的名字

  2. Union:将两个子集合并成同一个集合

  3. MakeSet: 用于建立单元素集合。

并查集的表示方法:

  1. 单链表表示

    要实现并查集数据结构,一种简单的方法是每一个集合都用一个链表来表示。每个链表的第一个对象作为它所在集合的代表。链表中的每一个对象都包含一个集合成员、一个指向包含下一个集合成员的对象的指针,以及指向代表的指针。每个链表都含head指针和tail指针,head指向链表的代表,tail指向链表中最后的对象。

  2. 并查集森林

    并查集的另一种更快的实现是用有根树表示集合树中每个节点包含一个成员,每棵树代表一个集合。在一个不相交森林中,每个成员仅指向指向它的父节点。每棵树的根包含集合的代表,并且是其自己的父节点。正如我们将要看到的那样,虽然使用这种表示的直接算法并不比使用链表表示的算法快,但通过引入两种启发式策略(“按秩合并”和“路径压缩"),我们能得到一个渐进最优的不相交集合数据结构。

    在这种表示方法中,MAKE-SET操作简单地创建一棵只有一个节点的树,Find操作通过沿着指向父节点的指针找到树的根。这一通过根节点的简单路径上所访问过的节点构成了查找路径。union操作使得一棵树指向另一棵树的根。下图所示为union操作:

    开始时每个集合含有一个元素。这些书不一定必须是二叉树,但是用二叉树表示起来要容易,因为我们需要的唯一信息就是父链(parent link)。集合的名字由根处的节点给出。由于只需要父节点的名字,因此可以假设这棵树是被非显式的存储在数组中(与二叉堆类似):数组的每个成员s[i]表示元素i的父亲。如果i是根,那么s[i]=-1.、

  

并查集森林的两种改进策略:

  1. 按秩合并(union by rank)。改进union操作的方法。这种方法的思想是在union操作中使较少节点的树的根指向具有较多节点的树的根。为了实现这种方法,我们需要记住每一棵树的大小。由于实际上使用了一个数组,因此可以让每个根的数组包含它的树的大小的负值。这样一来,初始时的数组表示就都是-1了。当执行一次union时,要检查树的大小;新的大小是原来的大小的和。这样桉大小秩求并的实现并不困难,并且不需要额外的空间,其平均速度也很快。

  2. 路径压缩(path compression)。改进find操作的方法。它在查找过程中将每个节点直接指向根。如下所示  

实现代码:

 1 class DisjSets {
 2  public:
 3     explicit DisjSets(int numElements);
 4
 5     int Find(int x);
 6
 7     void Union(int element1, int element2); // union is key word in C++, use Union
 8
 9  private:
10      vector<int> s;
11 };
12
13 DisjSets::DisjSets(int numElements): s(numElements) {
14     for (vector<int>::iterator iter = s.begin();
15          iter != s.end(); ++iter) {
16              *iter = -1;
17     }
18 }
19
20 //路径压缩
21 int DisjSets::Find(int x)  {
22     if (s[x] < 0)
23         return x;
24     else
25         return s[x] = Find(s[x]);
26 }
27
28 void DisjSets::Union(int element1, int element2) {
29     int root1 = Find(element1); //find root of element1
30     int root2 = Find(element2); //find root of element2
31
32     if (s[root2] < s[root1]) { //root2 is deeper
33         s[root1] = root2;      //Make root2 new root
34     } else {
35         if (s[root1] == s[root2])
36             s[root1]--;       //Update height id same
37         s[root2] = root1;     //Make root1 new root
38     }
39 }
时间: 2024-10-23 19:32:54

【经典数据结构】并查集的相关文章

POJ 1984 Navigation Nightmare (数据结构-并查集)

Navigation Nightmare Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 4072   Accepted: 1615 Case Time Limit: 1000MS Description Farmer John's pastoral neighborhood has N farms (2 <= N <= 40,000), usually numbered/labeled 1..N. A series o

POJ 1703 Find them, Catch them(数据结构-并查集)

Find them, Catch them Description The police office in Tadu City decides to say ends to the chaos, as launch actions to root up the TWO gangs in the city, Gang Dragon and Gang Snake. However, the police first needs to identify which gang a criminal b

读书笔记 之 数据结构(并查集详解)(POJ1703)

<ACM/ICPC算法训练教程>读书笔记-这一次补上并查集的部分.将对并查集的思想进行详细阐述,并附上本人AC掉POJ1703的Code. 在一些有N个元素的集合应用问题中,通常会将每个元素构成单元素集合,然后按照一定顺序将同属一组的集合合并,期间要反复查找每一个元素在哪个集合中.这类问题往往看似简单,但是数据量很大,因此容易造成TLE或MLE,也就是空间度和时间度极其复杂.因此在这里,我们引入一种抽象的特殊数据结构——并查集. 并查集:类似一个族谱,每个结点均有一个father[x]来表示x

HDU 1988 Cube Stacking (数据结构-并查集)

Cube Stacking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 18900   Accepted: 6568 Case Time Limit: 1000MS Description Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start w

poj 1611 :The Suspects经典的并查集题目

Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others.   In the Not-Spr

POJ1182 食物链---(经典种类并查集)

题目链接:http://poj.org/problem?id=1182 食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 69207   Accepted: 20462 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食

数据结构---并查集

并查集,顾名思义,合并 查找 集合: 并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.常常在使用中以森林来表示. 对于概念等等的这里不再赘述,直接讲解应用. [初始化] MakeSet,将每一个节点的父节点置为本身:rank(秩),是节点构成树的深度 void MakeSet(){ for(int i=1;i<=maxn;i++){ parent[i].value = i; parent[i].rank=0; } } [查找] 一直向上查找,直到

[经典算法]并查集

概述: 并查集(Union-find Sets)是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图.求最小生成树的 Kruskal 算法和求最近公共祖先(Least Common Ancestors, LCA)等. 使用并查集时,首先会存在一组不相交的动态集合 S={S1,S2,?,Sk},一般都会使用一个整数表示集合中的一个元素. 每个集合可能包含一个或多个元素,并选出集合中的某个元素作为代表.每个集合中具体包含了哪些元素是不关心的,具体选择哪个

实用数据结构---并查集

题目描述 Description 若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系. 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚.如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚. 输入描述 Input Description 第一行:三个整数n,m,p,(n<=5000,m<=5000,p<=5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系. 以下m行:每行两个数Mi,Mj,

数据结构--并查集的原理及实现

一,并查集的介绍 并查集(Union/Find)从名字可以看出,主要涉及两种基本操作:合并和查找.这说明,初始时并查集中的元素是不相交的,经过一系列的基本操作(Union),最终合并成一个大的集合. 而在某次合并之后,有一种合理的需求:某两个元素是否已经处在同一个集合中了?因此就需要Find操作. 并查集是一种 不相交集合 的数据结构,设有一个动态集合S={s1,s2,s3,.....sn},每个集合通过一个代表来标识,该代表中集合中的某个元素. 比如,若某个元素 x 是否在集合 s1 中(Fi