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. AutoCompleteTextView使用 监听

    AutoCompleteTextView使用 An editable text view that shows completion suggestions automatically while t ...

  2. hadoop 异常及处理总结-01(小马哥-原创)

    试验环境: 本地:MyEclipse 集群:Vmware 11+ 6台 Centos 6.5 Hadoop版本: 2.4.0(配置为自动HA) 试验背景: 在正常测试MapReduce(下简称MR)程 ...

  3. SharePoint咨询师之路:设计之前的那些事四:负载均衡 - web服务器

     提示:本系列只是一个学习笔记系列,大部分内容都可以从微软官方网站找到,本人只是按照自己的学习路径来学习和呈现这些知识.有些内容是自己的经验和积累,如果有不当之处,请指正. 容量管理 规模 体系结构 ...

  4. 第二百二十八天 how can I 坚持

    hibernate 还有好多不会搞啊,本来很简单的东西,没用过就不会. 今天... 只是感觉很累,昨天爬山爬的,不知道该写点啥了,买的羽绒服到了,还行吧,凑合穿吧. 睡觉了.今天貌似又发脾气了.哎.. ...

  5. CXF整合Spring发布WebService实例

    一.说明: 上一篇简单介绍了CXF以及如何使用CXF来发布一个简单的WebService服务,并且介绍了客户端的调用. 这一篇介绍如何使用CXF与spring在Web项目中来发布WebService服 ...

  6. 使用Windows Azure创建和发布ASP.NET应用程序

    Windows Azure为我们提供了一个功能强大的PaaS平台,使得我们无须部署和维护基础架构就可以根据需求发布开发的应用程序,并且支持多种语言及平台,如:ASP.NET, PHP, Python, ...

  7. UDP广播问题

    http://bbs.csdn.net/topics/390218123 Broadcast Address(广播地址)是专门用于同时向网络中所有工作站进行发送的一个地址.在使用TCP/IP 协议的网 ...

  8. CSS单词换行and断词

    背景 某天老板在群里反馈,英文单词为什么被截断了? 很显然,这是我们前端的锅,自行背锅.这个问题太简单了,css里加两行属性,分分钟搞定.   1 2 word–break: keep–all; wo ...

  9. Mac配置JAVA_HOME

    首先打开终端,输入/usr/libexec/java_home,看到 /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home 说 ...

  10. iOS的几种定时器

    //gcd的定时器timer必须先保存为一个属性或者成员变量 @property (nonatomic , assign) dispatch_source_t timer; //第一种 每一秒执行一次 ...