不相交集合数据结构保持一组不相交的动态集合S={S1,S2,...,SK},每个集合通过一个代表来识别,代表即集合中的某个成员。

如果x表示一个对象,不相交集合支持以下操作:

MAKE-SET(x):建立一个新的集合,其唯一成员为x。因为各集合是不想交的,故x没有在其它集合中出现。

UNION(x,y):将包含x和包含y的集合合并为一个新的集合。

FIND-SET(x):返回包含x的集合。

1.不相交集合的数组表示

在一个数组中保存每个元素所在集合的名称。这样Find操作就是简单的O(1)查找。要执行Union(x,y)操作,假设x在等价类i中,y在等价类j中,

扫描整个数组,将所有的i变为j。连续N-1次Union操作就要花费Θ(N2)的时间。如果Union操作很多,这个界是不可接受的。

2.不相交集合的链表表示

每一个集合用用一个链表来表示。链表的第一个对象作为它所在集合的代表。链表中每个对象都包含一个集合成员,一个指向下一个对象的指针,

以及指向代表的指针。每个链表含head和tail指针,head指向链表的代表,tail指向链表中最后的对象。

Union的简单实现:将x所在的链表拼接到y所在链表的表尾。对于原先x所在链表中的每一个对象都要更新其指向代表的指针。

平均看来,每个操作需要Θ(N)的时间。

加权合并:每个表含表的长度,总是将更短的表连接到长的表的后面。这样,m和MAKE-SET,UNION和FIND-SET操作要花费(m+nlgn)的时间。

class SetNode(object):
def __init__(self,key):
self.key=key
self.next=None
self.rep=None
class SetEntry(object):
def __init__(self):
self.head=None
self.tail=None
self.len=0
class DisjSet(object):
def __init__(self,node):
self.setlist=[]
def make_set(self,node):
S=SetEntry()
S.head=node
S.tail=node
S.len=1
node.rep=node
self.setlist.append(S)
def find(self,node):
return node.rep
def union(self,node_x,node_y):
rep_x=node_x.rep
rep_y=node_y.rep
if rep_x!=rep_y:
for s in self.setlist:
if s.head==rep_x:
set_x=s
elif s.head==rep_y:
set_y=s
if set_x.len>=set_y.len:
set_x.tail.next=rep_y
node=rep_y
while node is not None:
node.rep=rep_x
node=node.next
set_x.tail=set_y.tail
set_x.len=set_x.len+set_y.len
self.setlist.remove(set_y)
return rep_x
else:
set_y.tail.next=rep_x
node=rep_x
while node is not None:
node.rep=rep_y
node=node.next
set_y.tail=set_x.tail
set_y.len+=set_x.len
self.setlist.remove(set_x)
return rep_y

 3.不相交集合森林

使用树来表示一个集合,树的根用来作为集合的代表。树的每个节点都含有元素的数据以及一个指向父节点的指针。根节点的指针为空。

可以用数组来非显式的来表示树:数组的每个成员T[i]表示元素i的父节点,如果i是根,取p[i]为0或者-1。

如果任意执行Union操作,树可能会变为退化树,有几种方法可以避免这种情况

3.1 灵巧求并算法

总是让更小的树成为较大的树的子树,称为按大小求并。另一种方法是按高度求并。

这样的话,任何节点的深度都不会超过logN,Find操作的运行时间是O(logN),而连续M次操作则花费O(MlogN)。

实现时,让数组每个元素包含它的树的大小的负值。

class DisjSet(object):
def __init__(self,size):
self.list=[-1]*size
def find(self,x):
if self.list[x]<0:
return x
else:
return self.find(self.list[x])
def union(self,x,y):
set_x=self.find(x)
set_y=self.find(y)
if set_x!=set_y:
if self.list[set_x]>self.list[set_y]:
self.list[set_y]+=self.list[set_x]
self.list[set_x]=set_y
return set_y
else:
self.list[set_x]+=self.list[set_y]
self.list[set_y]=set_x
return set_x

3.2 路径压缩

路径压缩在一次Find(X)操作期间执行,从X到根的路径上的每一个节点都使它的父节点变成根。

路径压缩与按大小求并是完全兼容的,而不完全与按高度求并兼容。路径压缩时每棵树的高度会发生变化,可以对每棵树所存储的高度估计,用秩rank表示。

class DisjSet_with_rank(object):
def __init__(self,size):
self.list=[-1]*size
def find(self,x):
if self.list[x]<0:
return x
else:
self.list[x]=self.find(self.list[x])
return self.list[x]
def union(self,x,y):
set_x=self.find(x)
set_y=self.find(y)
if set_x!=set_y:
if self.list[set_x]<self.list[set_y]:
self.list[set_y]=set_x
else:
if self.list[set_x]==self.list[set_y]:
self.list[set_y]-=1
self.list[set_x]=set_y

路径压缩的显式表示  

class SetNode(object):
def __init__(self,key):
self.parent=None
self.key=key
self.rank=1
def find(node):
if node.parent is None:
return node
else:
node.parent=find(node.parent)
return node.parent
def union(x,y):
x=find(x)
y=find(y)
if x!=y:
if x.rank<=y.rank:
if x.rank==y.rank:
y.rank+=1
x.parent=y
return y
else:
y.parent=x
return x

  

不相交集合ADT的更多相关文章

  1. 不相交集合ADT -数据结构(C语言实现)

    读数据结构与算法分析 不相交集合 等价关系 满足三个性质 - 自反性 - 对称性 - 传递性 基本数据结构 基本思路 使用一个数组,下标表示该集合,内容表示指向的父亲 实现 类型声明 typedef ...

  2. 算法实践--不相交集合(Disjoint Sets)

    什么是不相交集合(Disjoint Sets) 是这样的一组set,任何元素最多只能在一个set中 至少支持查找Find和合并Union操作 实现方式(基于树) 每个set都是一棵树 每棵树都由树的根 ...

  3. 【并查集】 不相交集合 - 并查集 教程(文章作者:Slyar)

    最近写了一个多星期的并查集,一瞬间贴出这么多解题报告,我想关于并查集的应用先告一段落吧,先总结一下. 在网上看到一篇关于并查集比较好的教程(姑且允许我这么说吧),不转过来是在可惜.献给爱学习的你 文章 ...

  4. 并查集(不相交集合)详解与java实现

    目录 认识并查集 并查集解析 基本思想 如何查看a,b是否在一个集合? a,b合并,究竟是a的祖先合并在b的祖先上,还是b的祖先合并在a上? 其他路径压缩? 代码实现 结语 @(文章目录) 认识并查集 ...

  5. python学习笔记(集合的使用)

    集合 集合(set):把不同的元素组成一起形成集合,是python基本的数据类型. 集合元素(set elements):组成集合的成员 为什么需要集合? 集合的作用 1 .列表去重复数据 按照现有知 ...

  6. [学习笔记&教程] 信号, 集合, 多项式, 以及各种卷积性变换 (FFT,NTT,FWT,FMT)

    目录 信号, 集合, 多项式, 以及卷积性变换 卷积 卷积性变换 傅里叶变换与信号 引入: 信号分析 变换的基础: 复数 傅里叶变换 离散傅里叶变换 FFT 与多项式 \(n\) 次单位复根 消去引理 ...

  7. Java 知识笔记 - 类、集合、多线程、IO、JVM(最后一次更新,2019年02月17日)

    目录 Class 内部类.静态内部类.匿名内部类.局部内部类 Collection Java Collection Set Queue Map Collections Arrays System Co ...

  8. 图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用

    图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 ...

  9. Union-Find 检测无向图有无环路算法

    不相交集合数据结构(Disjoint-set data structure)是一种用于跟踪集合被分割成多个不相交的子集合的数据结构,每个集合通过一个代表来标识,代表即集合中的某个成员. Union-F ...

随机推荐

  1. oracle11g密码大小写敏感问题

    密码大小写敏感是Oracle 11g数据库默认的一个新特性,数据库配置助手(DBCA)在创建数据库期间允许你将这个设置返回到11g以前的功能. SEC_CASE_SENSITIVE_LOGON初始化参 ...

  2. oracle字段类型

    oracle 字段类型CHAR    固定长度字符串    最大长度2000    bytes              VARCHAR2    可变长度的字符串    最大长度4000    byt ...

  3. About gpref O(n2) --> O(1)

    http://www.ibm.com/developerworks/cn/linux/l-gperf.html 命令行处理和 gperf 的作用 命令行处理一直以来都是软件开发中最容易被忽视的领域.几 ...

  4. HTTPS证书制作

    openssl 安装可参照之前文章 1.mkdir /etc/ssl/xip.ioopenssl genrsa -out /etc/ssl/xip.io/xip.io.key 1024openssl ...

  5. html元素拖拽

    html <div> <div class="money-input"> 定投金额 : <div class="input-rela&quo ...

  6. css模块化思想(一)--------命名是个技术活

    引子: 女孩子都喜欢买衣服,而我也不例外,奈何钱包太瘦,买不起高大上的定制,只能买撞衫率极高的休闲衣,不过对于我来说,我还是开心的,毕竟买衣服买的不仅是衣服,更是一种心情.在web前端的世界里,css ...

  7. Ehcache - hello world

    Key Classes CacheManager The CacheManager class is used to manage caches. Creation of, access to, an ...

  8. h2database源码浅析:MVTable与MVIndex

    Database包含一个Store:MVTableEngine.Store getMvStore() MVTableEngine.Store可以获取各tables:java.util.HashMap& ...

  9. asp正则过滤重复字符串的代码

    asp下过滤重复字符串的代码,有时候我们需要过滤一些重复的字符串,下面的代码即可解决这个问题 比如 1223445677777778aabbcccccccccc 经过过滤之后就是12345678abc ...

  10. C# 打印文件

    这几天做的功能用到了打印这个功能,直接在网上找了点demo,在这里做个备份. 1.直接打印DataTable using System; using System.Collections.Generi ...