数据结构——不相交集

  在讨论不相交集数据结构之前,首先需要讨论等价关系。首先定义一下关系的概念:若对于每一对元素(a,b),a,bS,aRb或者为true或者为false,则称在集合S上定义关系R。如果aRb是true,那么a和b有关系。所谓的等价关系需要在关系的基础上满足下面三个性质:

1.(自反性)对于所有的aS,aRa。

2.(对称性)aRb当且仅当bRa。

3.(传递性)若aRb且bRc,则aRc。

  基于上面的定义可知,相等关系是一个等价关系,小于等于或者大于等于不是等价关系,因为不满足对称性。

  在等价关系基础之上,继续讨论动态等价性问题。假设给定属于同一个集合的两个元素a和b,需要判定这两个元素是否等价。一种思路是将等价关系存储为一个二维布尔数组,这样判断两个元素是否等价的操作可以在常数时间内完成。但是通常而言等价关系是不明显或者相当隐秘的,无法做到这么直观。为了解决这个问题,给出一个等价类的概念:一个元素aS的等价类是S的一个子集,它包含所有与a有关系的元素。等价类形成对S的一个划分,S中的每一个成员恰好出现在一个等价类中。为了确定a和b是否有等价关系,只需要验证a,b是否在同一个等价类中即可。

  在动态等价性问题中,初始的输入数据是n个集合的类,每个集合含有一个元素。在这些等价类上可以执行的操作是Find和Union操作。 其中Find操作返回包含给定元素的集合的名字。Union操作是用于添加关系的,它将不同的等价类(集合)合并到一起,并且删除被合并的两个原来的等价类。在动态等价问题的实现中,有两种思路,一种是使Find操作花费较少的时间,另一种是使Union操作花费较少的时间。下面描述的实现采用Union操作较为简单,Find操作要难一些。

基本数据结构

  这里的Find操作当操作于属于同一个不相交集合的两个元素上时,返回值应该是相等的。这里使用逻辑上的树结构来模拟这种操作,物理上使用数组来实现树这种逻辑结构,类似于堆的数组实现。选择树这种结构是因为属于同一颗树的元素有相同的根节点,在同一颗树上的节点上执行find操作可以返回树的根,这样就满足了不相交集的要求。当执行Union操作时,如果两个节点在同一个不相交集上,则不进行处理。如果两个节点不在同一个不相交集上,则合并两个不相交集。具体的操作是使一个根节点指向另一个根节点,即一棵树作为另一棵树的子树。初始情况下,每一个节点都是一棵树,这些树的集合为森林。使用数组数据结构来模拟树时,数组的索引就代表初始的数据元素(经过编号后的元素,每个索引代表一个元素)。数组在此索引处的值就代表其父节点,如果值为0,则这个索引代表的元素就是根节点。首先定义一下不相交集的类型声明:

#ifndef_DisjSet_H

typedef int DisJSet[NumSets+1];

typedef int SetType;

typedef int ElementType;

void Initilizalize(DisJSet S);

void SetUnion(DisJSet S,SetType Root1,SetType Root2);

SetType Find(ElementType X,DisJset S);

下面观察每个典型的方法,观察初始化例程:

void Initialize(DisJSet S)

{

int i;

for(i=NumSets;i>0;i--)

{

S[i]=0;

}

}

Find算法:(当索引值数组值为0是表明索引为根节点,返回,否则执行递归操作)

SetType Find(ElementType X,DisJSet S)

{

if(S[X]<=0)

return X;

else

return Find(S[X],S)

}

SetUnion(合并)算法:将一棵树作为另一棵树的子树

void SetUnion(DisJSet S,SetType Root1,SetType Root2)

{

S[Root2]=Root1;

}

灵巧求并算法

  使用上面的Union操作是相当任意的,它通过使第二棵树成为第一棵树的子树而完成合并。这种合并方法没有考虑其他的因素,导致有可能出现深度很深的树。从而在执行Find操作时花费更多的时间。可以使用两种不同的求并操作来改进并集操作使得两棵子树合并时不造成深度过深的情况。可以保证O(logN)的深度,即最大深度不超过logN。这两种方法分别是按大小求并和按照高度(秩)求并集。在实现中,仍然使用一个数组来模拟不相交集合,但是在不相交集的元素中需要保存树的大小或者高度信息。这里采用的方式是在根处保存树的大小或者高度的负数,这样在每一次合并操作时,首先判断两棵树的大小或者高度,将其中较小或者高度较低的树作为另一个树的子树。需要注意的是,在合并两个树后,需要更新作为根节点的树的大小或者深度。下面是按高度(秩)求并的程序:

void SetUnion(DisJSet S,SetType Root1,SetType Root2)

{

if(S[Root2]<S[Root1])

S[Root1]=Root2;

Else

{

if(S[Root1]==S[Root2])

S[Root1]--;

S[Root2]=Root1;

}

}

路径压缩

  在不相交集合上的一种改进是路径压缩操作,具体来说就是在每次执行Find操作时将从X到根的路径上的每一个节点都使它的父节点变成根。这样下次执行Find操作时可以减少向根处递归查找的次数。例程如下:

SetType Find(ElementType X,DisjSet S)

{

if(S[X]<=0)

return X;

else

return S[X]=Find(S[X],S);

}

时间: 2024-10-13 01:07:49

数据结构——不相交集的相关文章

数据结构与算法分析(四)——不相交集

基本介绍 一个集合S,集合中一个元素a.a的等价类是S的一个子集,该子集包含所有与a有关系的元素. 等价类形成是对S的一个划分且S中的每一个成员恰好出现在一个等价类中.这样,判断a与b是否有关系, 只需要判断a与b是否在一个等价类中即可. 对于集合S划分,取任意两个等价类,Si与Sj,如果Si∩Sj = ∅,则称这些集合不相交. 对于不相交集,有两种操作,Union/Find操作.Find操作找包含给定元素的集合(等价类)名字. Union把两个等价类合并成一个新的等价类. 数据结构:采用树来表

[数据结构与算法分析(Mark Allen Weiss)]不相交集 @ Python

最简单的不相交集的实现,来自MAW的<数据结构与算法分析>. 代码: class DisjSet: def __init__(self, NumSets): self.S = [0 for i in range(NumSets+1)] def SetUnion(self, S, Root1, Root2): S[Root2] = Root1 def Find(self, X, S): if S[X] <= 0: return X else: return self.Find(S[X],

数据结构与算法——不相交集类的C++实现

简介: 不相交集类是将一些元素合并为不相交的各个集合.在同一个集合中的元素两两等价,不同集合中的元素不等价. 1.等价关系 等价关系必须满足下面三个性质: (1):自反性,对于集合S中的任意元素a,a R a;(R为定义的关系,比如R为<=, >=等等) (2);对称性,a R b当且仅当b R a (3):传递性,若a R b且b R c,则a R c 2.动态等价性问题 集合S中元素a的等价类是集合S的一个子集,该等价类中包含所有与a有等价关系的元素.所以为确定a是否等价b,只需要验证a和

利用不相交集类制作迷宫游戏(数据结构课程设计——迷宫老鼠)

之前大一的时候有几天闲来无事,为了学习做了一个可以自动生成迷宫,可以寻找最短路径的小游戏,现在整理分享一下 简单介绍: 利用不相交集类考虑一个迷宫的生成,一个简单算法就是从各处的墙壁开始(除入口和出口之外).此时,不断地随机选择一面墙,如果被该墙分割的单元彼此不联通,那么就把这面墙拆掉.重复这个过程直到开始单元和终止单元联通,那么就得到一个迷宫.实际上不断的拆掉墙壁直到每个单元都可以从其他单元到达更好(这会使迷宫产生更多误导的路径). 整理一下迷宫的生成算法就是: (1)将迷宫初始时看成一个一个

不相交集ADT--数组实现

不相交集是解决等价问题的一种有效的数据结构,之所以称之为有效是因为,这个数据结构简单(几行代码,一个简单数组就可以搞定),快速(每个操作基本上可以在常数平均时间内搞定). 首先我们要明白什么叫做等价关系,而在这个之前要先有一个关系(relation)的定义 Relation:定义在数据集S上的关系R是指,对于属于数据集S中的每一对元素(a,b),a R b要么是真要么是假.如果a R b为真,就说a related b,即a与b相关. 等价关系也是一种关系(Relation),只不过是要满足一些

《数据结构与算法分析—C语言描述》pdf

下载地址:网盘下载 内容简介 编辑 <数据结构与算法分析:C语言描述(原书第2版)>内容简介:书中详细介绍了当前流行的论题和新的变化,讨论了算法设计技巧,并在研究算法的性能.效率以及对运行时间分析的基础上考查了一些高级数据结构,从历史的角度和近年的进展对数据结构的活跃领域进行了简要的概括.由于<数据结构与算法分析:C语言描述(原书第2版)>选材新颖,方法实用,题例丰富,取舍得当.<数据结构与算法分析:C语言描述(原书第2版)>的目的是培养学生良好的程序设计技巧和熟练的算

不相交集python实现

1.不相交集是解决等价关系的一种数据结构,执行合并和查找的速度都非常快,M次运行合并和查找的运行时间为(M*logN). 在一个集合中,对于每一对元素(a,b),a,b∈S,对于关系R如果满足下面三个条件,则成关系R为等价关系: (1)自反性  对于所有a∈S,aRa (2)对称性   aRb当且仅当bRa (3)传递性   若aRb且bRc,则aRc 有关不相交集的介绍和C语言实现,点此查看 本文介绍的是不相交集的find和union操作的python实现: def init(a): for

不相交集(The Disjoint Set ADT)

0)引论 不相交集是解决等价问题的一种有效的数据结构,之所以称之为有效是因为,这个数据结构简单(几行代码,一个简单数组就可以搞定),快速(每个操作基本上可以在常数平均时间内搞定). 首先我们要明白什么叫做等价关系,而在这个之前要先有一个关系(relation)的定义 Relation:定义在数据集S上的关系R是指,对于属于数据集S中的每一对元素(a,b),a R b要么是真要么是假.如果a R b为真,就说a related b,即a与b相关. 等价关系也是一种关系(Relation),只不过是

浅入浅出数据结构(25)——最小生成树问题

上一篇博文我们提到了图的最短路径问题:http://www.cnblogs.com/mm93/p/8434056.html.而最短路径问题可以说是这样的一个问题:路已经修好了,该怎么从这儿走到那儿?但是在和图有关的问题中,还有另一种有趣的问题:修路的成本已经知道了,该怎么修路才能尽可能节约成本,同时将这些地方都连起来? 比如我们知道有这么几个城市,它们互相之间还没有路: 经过实地考察后,发现可以修的路以及各条路的修路成本如下: 但是我们的预算有限,需要在修路时尽可能的省钱(也就是尽量减小所有边的