算法导论学习笔记(15)——用于不相交集合的数据结构

来源:互联网 发布:hydra软件免费下载 编辑:程序博客网 时间:2024/05/16 06:46

 用于不相交集合的数据结构

总结:这一章讲了并查集的相关概念,以及主要的MAKE-SET, UNION, FIND-SET操作,并给出了并查集的链表表示和森林表示方式。

1.    不相交集合上的操作

不相交集合数据结构保持一组不相交的动态集合,每个集合通过一个代表来标识,代表即集合中的某个成员。

一些操作:

MAKE-SET(x): 建立一个新的集合,其唯一成员为x。

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

FIND-SET(x): 返回一个指针,指向包含x的集合的代表。

应用:例如,确定一个无向图中连通子图的个数。

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

每一个集合用一个链表表示。每个链表中的第一个对象作为它所在集合的代表。

每一个对象的结构:

1)集合成员

2)指向包含下一个集合成员的对象的指针

3)指向代表的指针

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

MAKE-SET(x): O(1),创建新链表,其仅有对象为x

FIND-SET(x): O(1),返回x指向代表的指针

UNION(x,y): 将x所在的链表拼接到y所在链表的表尾。注意,对于原先x所在链表中的每一个对象,都需要更新其指向代表的指针。

加权合并启发式策略:设每个表还包括了表的长度,合并时,总是把较短的表拼到较长的表上。

使用加权合并策略,对m个MAKE-SET, UNION和FIND-SET操作所构成的序列(其中n个MAKE-SET操作,因此UNION操作的次数至多为n-1),花费的总时间为O(m+nlgn)。

3.    不相交集合森林

利用有根树来表示集合,每棵树表示一个集合。树中的每个成员仅指向其父节点,树的根的父节点仍是自己,且树的根即集合的代表。

启发式策略:

1)按秩合并

合并时,使包含较少结点的树的根指向包含较多结点的树的根。秩,结点高度的上界。因此,即,具有较小秩的根在UNION操作中要指向具有较大秩的根。

2)路径压缩

在FIND-SET操作中,使查找路径上的每个结点都直接指向根节点。

设rank[x]表示结点的秩,即x的高度的上界,p[x]表示x的父节点

伪代码

MAKE-SET(x)

p[x] <- x

rank[x] <- 0

伪代码

UNION(x,y)

LINK(FIND-SET(x),FIND-SET(y))

伪代码

LINK(x,y)

if rank[x] > rank[y]

      then p[y] <- x

      else p[x] <- y

            if rank[x]=rank[y]

                 then rank[y] <- rank[y]+1

伪代码

FIND-SET(x)

if x!=p[x]

      then p[x] <- FIND-SET(p[x])

return p[x]

FIND-SET采用了两趟方法:一趟沿查找路径上升,直至找到根;第二趟沿查找路径下降,以便更新每个结点,使之直接指向根。

分析:当同时采用按秩合并和路径压缩时,对m个MAKE-SET, UNION, FIND-SET的操作序列,总的运行时间可看作与m成线性关系。

附录:

[cpp] view plaincopyprint?
  1. typedef struct _node 
  2.     _node* parent; 
  3.     int rank; 
  4. }node; 
  5.  
  6. node *s[5000]; 
  7.  
  8. void makeSet(int x) 
  9.     s[x]=new node; 
  10.     s[x]->rank=0; 
  11.     s[x]->parent=s[x]; 
  12.  
  13. node* findSet(node* s) 
  14.     if(s!=s->parent) 
  15.     { 
  16.         s->parent=findSet(s->parent); 
  17.     } 
  18.     return s->parent; 
  19.  
  20. void link(node *s1, node *s2) 
  21.     if(s1==s2) 
  22.         return; 
  23.     if(s1->rank > s2->rank) 
  24.         s2->parent=s1; 
  25.     else 
  26.     { 
  27.         s1->parent=s2; 
  28.         if(s1->rank==s2->rank) 
  29.             s2->rank++; 
  30.     } 
  31.  
  32. void _union(node *s1, node *s2) 
  33.     link(findSet(s1),findSet(s2)); 

原创粉丝点击