不相交集合数据结构保持一组不相交的动态集合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)的时间。

  1. class SetNode(object):
  2. def __init__(self,key):
  3. self.key=key
  4. self.next=None
  5. self.rep=None
  6. class SetEntry(object):
  7. def __init__(self):
  8. self.head=None
  9. self.tail=None
  10. self.len=0
  11. class DisjSet(object):
  12. def __init__(self,node):
  13. self.setlist=[]
  14. def make_set(self,node):
  15. S=SetEntry()
  16. S.head=node
  17. S.tail=node
  18. S.len=1
  19. node.rep=node
  20. self.setlist.append(S)
  21. def find(self,node):
  22. return node.rep
  23. def union(self,node_x,node_y):
  24. rep_x=node_x.rep
  25. rep_y=node_y.rep
  26. if rep_x!=rep_y:
  27. for s in self.setlist:
  28. if s.head==rep_x:
  29. set_x=s
  30. elif s.head==rep_y:
  31. set_y=s
  32. if set_x.len>=set_y.len:
  33. set_x.tail.next=rep_y
  34. node=rep_y
  35. while node is not None:
  36. node.rep=rep_x
  37. node=node.next
  38. set_x.tail=set_y.tail
  39. set_x.len=set_x.len+set_y.len
  40. self.setlist.remove(set_y)
  41. return rep_x
  42. else:
  43. set_y.tail.next=rep_x
  44. node=rep_x
  45. while node is not None:
  46. node.rep=rep_y
  47. node=node.next
  48. set_y.tail=set_x.tail
  49. set_y.len+=set_x.len
  50. self.setlist.remove(set_x)
  51. return rep_y

 3.不相交集合森林

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

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

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

3.1 灵巧求并算法

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

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

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

  1. class DisjSet(object):
  2. def __init__(self,size):
  3. self.list=[-1]*size
  4. def find(self,x):
  5. if self.list[x]<0:
  6. return x
  7. else:
  8. return self.find(self.list[x])
  9. def union(self,x,y):
  10. set_x=self.find(x)
  11. set_y=self.find(y)
  12. if set_x!=set_y:
  13. if self.list[set_x]>self.list[set_y]:
  14. self.list[set_y]+=self.list[set_x]
  15. self.list[set_x]=set_y
  16. return set_y
  17. else:
  18. self.list[set_x]+=self.list[set_y]
  19. self.list[set_y]=set_x
  20. return set_x

3.2 路径压缩

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

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

  1. class DisjSet_with_rank(object):
  2. def __init__(self,size):
  3. self.list=[-1]*size
  4. def find(self,x):
  5. if self.list[x]<0:
  6. return x
  7. else:
  8. self.list[x]=self.find(self.list[x])
  9. return self.list[x]
  10. def union(self,x,y):
  11. set_x=self.find(x)
  12. set_y=self.find(y)
  13. if set_x!=set_y:
  14. if self.list[set_x]<self.list[set_y]:
  15. self.list[set_y]=set_x
  16. else:
  17. if self.list[set_x]==self.list[set_y]:
  18. self.list[set_y]-=1
  19. self.list[set_x]=set_y

路径压缩的显式表示  

  1. class SetNode(object):
  2. def __init__(self,key):
  3. self.parent=None
  4. self.key=key
  5. self.rank=1
  6. def find(node):
  7. if node.parent is None:
  8. return node
  9. else:
  10. node.parent=find(node.parent)
  11. return node.parent
  12. def union(x,y):
  13. x=find(x)
  14. y=find(y)
  15. if x!=y:
  16. if x.rank<=y.rank:
  17. if x.rank==y.rank:
  18. y.rank+=1
  19. x.parent=y
  20. return y
  21. else:
  22. y.parent=x
  23. 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. careercup-中等难题

    17.1 编写一个函数,不用临时变量,直接交换两函数. 解法: 方法一:这个是经典面试题,也相当直接.我们将用a0表示a的初值,b0表示b的初始值,用diff表示a0-b0的值. 让我们将a>b ...

  2. JavaScript网站设计实践(六)编写live.html页面 改进表格显示

    一.编写live.html页面,1.JavaScript实现表格的隔行换色,并且当鼠标移过时当前行高亮显示:2.是输出表格中的abbr标签的内容 实现后的效果图是这样的: 1.实现思路 在输出表格的时 ...

  3. 第一个js程序

    <html><head> <title>Untitled</title> <script >function demo(){ alert ( ...

  4. oracle 不转义 &

    在为表加注释,遇到有些注释包含'&' 但又不想写eacape, 在sqlplus下,set define off   即可将&输入到数据库中.

  5. VSPackge插件系列:如何正确获取DTE

    做VS插件开发,不得不了解DTE,有了DTE我们就可以与VS交互了,比如说获取当前选择的文件,比如说获取当前主窗口,比如说获取编译器等等,关于DTE接口更多的说明我把接口地址贴出来方便大家查阅. ht ...

  6. 关于JFace带复选框的树

    树的复选框用CheckboxTreeViewer实现.由于其子类ContainerCheckedTreeViewer在没有选择全部子节点时可以自动将父节点设置成灰选,所以实现树的复选框更多的是用Con ...

  7. [记录]java.math.biginteger cannot be cast to java.lang.long

    可以直接使用BigInteger类型进行接收, BigInteger id = (BigInteger)QueryRunner(conn,"SELECT LAST_INSERT_ID&quo ...

  8. C语言碰到的一元二次方程

    最近开始在学习C语言,看视频,是http://www.rjzxw.com/jc-74-1.html 碰到老师讲的一元二次方程例子,不懂,所以找了下资料,看了网上一元二次方程的视频(是自己太浮躁了,听不 ...

  9. Android的几种alert对话框

    @Override public void onClick(View v) { switch (v.getId()) { case R.id.d1: AlertDialog.Builder build ...

  10. sql2008存储过程解密。

    今天有一个同事在做一个项目的时候,因为现在公司不跟某一家公司合作.有一些sql的存储过程是加密,现在想打开那些存储过程来解密.故查看了一些资料终于解密成功.步骤如下: 1.需要开始DAC连接. 1.1 ...