0)引论

不相交集是解决等价问题的一种有效的数据结构,之所以称之为有效是因为,这个数据结构简单(几行代码,一个简单数组就可以搞定),快速(每个操作基本上可以在常数平均时间内搞定)。

首先我们要明白什么叫做等价关系,而在这个之前要先有一个关系(relation)的定义

Relation:定义在数据集S上的关系R是指,对于属于数据集S中的每一对元素(a,b),a R b要么是真要么是假。如果a R b为真,就说a related b,即a与b相关。

等价关系也是一种关系(Relation),只不过是要满足一些约束条件

a) a R a,对于所有属于S的a

b) a R b 当且仅当 b R a

c) a R b 并且 b R a 意味着 a R c

动态等价性问题:

定义在非空集合S上的关系R,对于任意属于数据集S中的每一对元素(a,b),确定a R b是否为真,也就是说a与b是否有关系。

而对于a与b是否有关系,我们只需要证明a与b是否在同一个等价类集合中。

1)基本结构

Find操作:返回给定元素的集合的名字,也就是检查a,b是否在同一个等价类中。对于Find运算,最重要的是判断Find(a,S) == Find(b,S)是否成立。

Union操作:如果a,b不在一个等价类中,可以用Union操作把这连个等价类合并为一个等价类。

我们可以用tree结构来表示一个集合,root可以表示集合的名字。由于仅有上面的两个操作而没有顺序信息,因此我们可以将所有的元素用1-N编号,编号可以用hashing方法。

进一步可以发现对于这两个操作无法使其同时达到最优,也就是说当Find以常数最坏时间运行时,Union操作会很慢,同理颠倒过来。因此就有了2种实现方式。

a)使Find运行快

在数组中保存每个元素的等价类的名字,将所有等价类的元素放到一个链表中

b)使Union运行快

使用树来表示每一个集合,根节点表示集合的名字。数组元素P[i]表示元素i的父亲,若i为root,则P[i]=0。

对于Union操作,相当于把连个树合并,也就是指针的移动,如下图所示:

typedef int DisjSet[NumSets+];
typedef int SetType; void initialize(DisjSet S)
{
int i;
for(i=NumSets;i>;i--)
s[i]=;
}
void SetUnion(DisjSet S, SetType Root1, SetType Root2)
{
S[Root2] = Root1;
} SetType Find(ElementType X, DisjSet S)
{
if(S[x]<=)
return x;
else
return Find(S[x],S);
}

对于Find操作就是一个不断返回父节点知道找到根节点的递归过程。

2)灵巧合并算法

上面的合并算法相当随意,它就是把第二棵树作为第一棵树的子树来完成合并操作。有一个简单的改进方法是总是让较小的树成为较大的树的子树,这种方法叫做Union-by-Size,如下图所示Union-by-Size可以降低树的深度,每个节点的深度都不会超过O(logN)。

为了实现这种方法,必须记录每一棵树的大小。我们可以另每一个根节点的数组元素表示树的大小的赋值,非根节点不变,依旧表示其父节点。这其实是把上面方法的数组中的0的位置做了一些利用。

另一种方法是Union-by-Height,也就是说我们把高度较浅的树作为高度较深的树的子树。亦即根节点记录的是树的高度的负值。

Union-by-Height的Union代码实现

void SetUnion(DisjSet S, SetType Root1, SetType Root2)
{
//add the low height tree to the high height tree.
if(S[Root2]<S[Root1])
S[Root1] = Root2;
else
{
if(S[Root1] = S[Root2]) //same height
S[Root1]--;
S[Root2] = Root1;
}
}

3)路径压缩

随着树的加深,Find操作的时间会增加。如果Find操作比Union操作多的多的话,那么运算时间会相当糟糕,比快速查找还要差。而且从上面可以看出,Union算法的改进比较困难,因此我们应该尝试去使Find更加高效。这就引入了path compression。

路径压缩:在Find操作期间执行与Union操作无关,路径压缩的效果是从X到根节点的路径上的每一个结点都使它的父节点成为根节点。

代码实现:

SetType Find(ElementType X, DisjSet S)
{
if(S[x]<=)
return x;
else
return S[x] = Find(S[x],S);
}

和上面相比,代码只有一点点小修改。

路径压缩算法是与Union-by-Size相兼容的,与Union-by-Height并不完全兼容。

4)小应用

说了这么多,这个数据结构总要有点用处啊,否则就没有什么意义了。

一个例子是计算机网络和双向连接表,每一个连接将文件从一个计算机传递到另一个计算机。现在的问题是能否将文件从任意一个计算机传递到另一个任意的计算机,并且这个问题要on-line解决。

解决这个问题,就可以用到上面的数据结构。开始阶段我们可以把每一台计算机放到他自己的集合中,要求两台计算机传递文件当且仅当这两台计算机在同一个集合中。因此传输文件能力相当于一个等价关系。当我们需要传输文件时,检验两个计算机是否在同一个集合里,是的话就传输文件,否的话,就用Union方法把它们合并到一个集合中,然后传输文件。

5)总结

不相交集是一个非常简单的数据结构,仅用几行代码就可以搞定。对于Find操作,重要的是Find(a,S) == Find(b,S)为真还是假。Union操作有很多种实现,比较灵活。为了节省Find操作的时间,引入了路径压缩算法,这是自调整(self-adjustment)的最早形式之一。

不相交集(The Disjoint Set ADT)的更多相关文章

  1. 不相交集ADT 你是和谁是一类人?

    //不相交集ADT (抽象数据类型) //一般用于集合运算 //用树,这种结构组成,有多个树(=森林) //属于同一颗数的元素,表示处于同一个集合中 //主要支持2个操作. //1. Find操作,找 ...

  2. 并查集(disjoint set)的实现及应用

    这里有一篇十分精彩.生动的 并查集详解 (转): "朋友的朋友就是朋友"⇒ 传递性,建立连通关系 disjoint set,并查集(一种集合),也叫不相交集,同时也是一种树型的数据 ...

  3. Android Studio vs. Eclipse ADT Comparison

    Android Studio 是一个新的基于 IntelliJ IDEA Android 的安卓开发环境,它对 Eclipse ADT 进行了改进并新增了功能. Feature Android Stu ...

  4. ADT - Eclipse 常用快捷键

    ADT - Eclipse 常用快捷键 Alt + / : 自动补全 F3 : 打开类的源码 Ctrl + D : 删除选中行 Ctrl + 1 : 自动弹出修改建议 Ctrl + Shift + J ...

  5. [LeetCode] Data Stream as Disjoint Intervals 分离区间的数据流

    Given a data stream input of non-negative integers a1, a2, ..., an, ..., summarize the numbers seen ...

  6. ADT for Eclipse无法升级到23.0的解决方法(确保您的网络能够访问google的地址)

    进行以下步骤时,请确保您的网络能够访问google的地址,因为有可能是无法访问google地址导致无法升级,该文不是为了解决这个问题!!! 最近一次的升级,ADT无法从ADT 22.X升级到23.0. ...

  7. 搭建Android开发环境附图详解+模拟器安装(JDK+Eclipse+SDK+ADT)

    ——搭建android开发环境的方式有多种,比如:JDK+Eclipse+SDK+ADT或者JDK+Eclipse+捆绑好的AndroidSDK或者Android Studio. Google 决定将 ...

  8. ADT + JNI实例

    Author: Maddock Date: 2015-07-09 本文简单记录了Android中利用jni开发程序初级教程: 步骤 1 下载安装ADT 2 配置NDK 3 新建安卓工程 4 测试jni ...

  9. Windows下ADT环境搭建

    1.JDK安装 下载JDK(点我下载),安装成功后在我的电脑->属性->高级->环境变量->系统变量中添加以下环境变量: JAVA_HOME值为C:\Program Files ...

随机推荐

  1. make subversion时出现neon报错 及 svn其他问题汇总(3ge )

    在make subvision时,出现以下错误提示: /usr/local/src/neon-0.29.6/src/ne_auth.c:781: undefined reference to`ne__ ...

  2. [LeetCode] #167# Two Sum II : 数组/二分查找/双指针

    一. 题目 1. Two Sum II Given an array of integers that is already sorted in ascending order, find two n ...

  3. ajax 加载不同数据

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  4. 关于 python 的 @property总结和思考

    其实关于@property我到处去搜了很多教程来看,因为公司大量使用了oop的编程而我以前很少写,所以现在来重新补过来. 从使用上来说 加了@property之后最明显的区别就是 class Stud ...

  5. 第三百五十二天 how can I 坚持

    如果要是今年找不到对象,明年去回济南, 怎么感觉那么不舍呢.生活总是有太多的无奈啊. 今天加了一天,倒是没感觉,只是感觉生活太空虚. 或许遗憾只是因为自己太懦弱.怎么说呢,还是那句话,经历的就会成长, ...

  6. error日志

    2016/06/15 微信调核心时通用意外险 2016-06-15 11:44:23,771>>INFO >> com.isoftstone.core.service.comm ...

  7. hdu 1155 Bungee Jumping

    http://acm.hdu.edu.cn/showproblem.php?pid=1155 Bungee Jumping Time Limit: 2000/1000 MS (Java/Others) ...

  8. HDU 5432 Rikka with Tree (BestCoder Round #53 (div.2))

    http://acm.hdu.edu.cn/showproblem.php?pid=5423 题目大意:给你一个树 判断这棵树是否是独特的 一颗树是独特的条件:不存在一颗和它本身不同但相似的树 两颗树 ...

  9. oracle学习 二(持续更新中)

    oracle数据库的启动停止 以oracle用户身份登录 登录后输入以下命令: oracle-> sqlplus /nolog SQL*Plus: Release 9.2.0.1.0 - Pro ...

  10. linux 下查看文件个数及大小

    ls -l |grep "^-"|wc -l   或      find ./company -type f | wc -l 查看某文件夹下文件的个数,包括子文件夹里的. ls - ...