第6章 集合与字典
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
求单链表表示集合的交集
int intersectionLink (LinkSet s0,LinkSet s1,LinkSet s2)
在有序链表表示的集合中,在s1中找到第一个与s0中 相同元素后,其它共同元素不需要从头开始比较,只 要从刚才比较成功所结束的位置继续向后检索。 因此,只要用两个指针,沿s0和s1从头至尾扫描一遍 即可完成。当这两个表的长度为n1和n2时,算法的 时间总花费最多为O(n1+n2)。
在实践中使用较多的字典里所有的关键码互不相同, 这种关键码具有唯一性的字典,在数学中称为映射 (mapping),数据结构里讲的就是这种字典。 字典关心的最主要的运算是检索。
衡量一个字典检Fra Baidu bibliotek算法效率的主要标准是检索过程中 对关键码的平均比较次数: n ASL p i c i
i 1
以及算法的空间开销、算法是否易于理解等因素。
链表中的每个结点表示集合中的一个元素,具体 方式与第二章单链表的结点struct Node类似。 不同之处在于:线性表的单链表中,link字段表示 线性表元素之间的逻辑后继关系,而在这里仅仅 是把属于同一集合的所有元素链接成一个整体。 因为我们讨论的是有序集,如果将集合中的所有 元素按“<”关系排序构造有序链表,给集合的 某些运算会带来方便。
存储结构
假设需要表示的集合的公共超集中,共有n个不同的 元素,为叙述的方便,不妨假设这些元素就是整数0, 1,2,…,n-1等。 每个集合可以采用一个有n位的位向量来表示。若整 数i是这个集合的一个元素,则位向量中对应的位为 1(真),否则为0(假)。
由于在C语言中无法直接定义位数组,要定义位向 量,需要借助其它方式。一种比较自然的方式,是 用长度为n/8的字符数组表示长度为n的字位数组。 一个字符用8位二进制编码,它实际上包含了8个二 进制位。
空集合的创建
与空顺序表的的创建类似,不同之处在于这里省 略了每个集合中实际元素个数的变量: BitSet * createEmptySet (int n)
将整数index的元素插入集合
将值为index的元素插入集合S的过程,通过将位 向量中下标为index的位置为1来完成: int insert (BitSet * s, int index)
在字典dic中检索关键码为key的关联的位置p。
int insert(Dictionary dic, DicElement ele) 在字典dic中插入关联ele。 int delete(Dictionary dic, KeyType key) 在字典dic中删除关键码为key的关联。 end ADT Dictionary
将整数index的元素从集合中删除
通过将位向量中下标为index的位置为0来完 成: int delete(BitSet * s, int index)
判断整数index的元素是否属于集合
通过判断位向量中下标为index的位是否为1 来完成: int member(BitSet * s, int index)
int difference(Set A,Set B,Set C) 求集合A和B的差集,结果在集合C中。 int subset(Set A,Set B) 当且仅当A是B的子集时,函数值才为真。 end ADT Set
6.2 集合的实现
位向量表示 单链表表示
6.2.1 位向量表示
位向量是一种每个元素都是二进制位(即0/1值) 的数组。当表示的集合存在某个不太大的公共超 集时,采用位向量的方式来表示这种集合往往十 分有效。
列举法: 定义一个有穷集,可以将成员放在一对花括号中,成员
之间用逗号隔开。 例如{1,2,4}
谓词描述法:
空集 子集 超集
I {x| Z ( x) x 0}
集合的大小: 集合中所包含的元素的个数。
数据结构中讨论的集合,一般有以下限制:
1)数据结构讨论的集合总限制为有穷集;
2)假定集合中所有元素属同一类型;并且假设元素之间 存在一个小于关系“<”,也称为有序集。
插入运算首先要找到适当的插入位置,它有 两个参数:一个是被插入元素的信息 x;另 一个则是被插入的集合s0。
程序实现
6.3 字典及其抽象数据类型 6.3.1基本概念
字典是一种集合,其中每个元素由两部分组成,分别称 为关键码和属性(或称为值)。这种包含关键码和属性的 二元组称作关联(Association)。 抽象地看,一个关联是一个有序对,它可以看成是由关 键码值k到属性(值)v的一个对应。字典就是由关键码集 合到值集合的二元关系。 字典中的元素之间能够根据其关键码进行比较大小,对 字典元素的插入、删除和检索等操作一般也以关键码为 依据进行。 D { k , v | k K v V }
6.1 集合及其抽象数据类型 6.1.1 基本概念 6.1.2 主要运算 6.1.3 抽象数据类型 6.2 集合的实现 6.2.1 集合的位向量表示 6.2.2 集合的单链表表示 6.3 字典及其抽象数据类型 6.3.1 基本概念 6.3.2 抽象数据类型
6.4 字典的顺序表示 6.4.1 存储结构 6.4.2 算法的实现 6.4.3 有序顺序表 与二分法检索 6.5 字典的散列表示 6.5.1 基本概念 6.5.2 散列函数 6.5.3 碰撞的处理 6.5.4 散列文件
程序实现
集合的赋值
int assignLink (LinkSet s0,LinkSet s1) 赋值运算将集合s0拷贝成集合s1,注意这一 运算不能简单地将 s0 的表头结点置成 s1 的 表头结点,因为若这样处理,则对 s1 的改 变将会带来s0的改变。
程序实现
插入运算 int insertLink (LinkSet s0,DataType x)
集合与集合的并
利用按位的“或”运算实现: int union (BitSet * s0, BitSet * s1, BitSet * s2)
集合与集合的交
这个运算很容易通过位“与”操作实现。 int intersection(BitSet * s0, BitSet * s1, BitSet * s2)
集合与集合的差
将第一个集合与第二个集合的逆做与运算,就可以达到 这个目的。 int difference(BitSet * s0, BitSet * s1, BitSet * s2)
6.2.2 单链表表示
链接表示方式下,在链表中存放的是集合中元素 的实际数值,而不是元素是否属于集合的标记。
存储结构
6.4 字典的顺序表示
6.4.1 存储结构
从逻辑结构出发,字典中的元素是无序的,但为了实现的方便, 可以把字典中的元素按关键码的大小组织成一个顺序表。
typedef int
KeyType;
typedef int
typedef struct { KeyType key;
6.1 集合及其抽象数据类型 6.1.1 基本概念
集合是数学中最基本的概念,也是一种基本数据结构。 在数学中,集合是一些互不相同元素的无序汇集。这 些元素称为该集合的成员。集合中的成员可以是一个 原子(不可再分解);也可以是一个结构,甚至又是 一个集合。集合中的各个元素应该是互不相同的。
x A, x A
6.1.2 主要运算
集合也可以定义测试一个元素是否存在于集合中、增加一个元素、删除一 个元素等运算,但集合更加关心下面的一些运算。 求并集: A B 求交集: 求差集:
{x | x A x B}
A B {x | x A x B}
A-B {x | x A x B}
上面集合间的运算,都可以通过增加元素、 删除元素和成员测试等运算来实现。
例如: 已知集合A和B,求它们的并集,只要以集合A (或B)为基础,把集合B(或A)的元素逐个插 入。 如果要求两个集合的交集,只要从A(或B)出发, 检查各元素是否在B(或A)中出现,把那些也在 另一个集合里出现的元素插入(初态为空集)的 集合中即可。 求A与B的差集A−B时,只要以A为基础,对每个B 中的元素做删除运算即可。
第六章 集合与字典
从逻辑结构上看,集合和字典都是最简单的数据结构,它 们的元素之间没有任何确定的依赖关系。
字典是关联的集合。 作为抽象数据类型,集合和字典之间的主要区别,在于它 们的操作。 集合主要考虑集合之间的并、交和差操作; 字典主要关心其元素的检索、插入和删除。
目录
子集: A是B的子集
x( x A x B)
如果集合A是B的子集,反过来也称集合B是A的超集。 相等:
A B A BB A
例如:若A={a,b,c},B={b,d},则有A∪B={a,b, c,d},A∩B={b},A-B={a,c}。另外,A不等于B, 同时A和B相互都不是子集关系。 ……
struct Node; typedef struct Node *PNode;
struct Node {
DataType info;
PNode
};
link;
typedef struct Node *LinkSet;
集合S={0,1,2,…,n-1}采用带表头结点的有 序链表表示时,如图所示:
算法实现
位运算
假设x和y都是8位的字符,其值分别是: X= 01010111 Y= 11011010。 对x和y做各种字位运算,得到的结果如下: ~x 10101000 x & y 01010010 x^y 10001101 x|y 11011111 x << 3 10111000 y >> 5 00000110
6.1.3 抽象数据类型
ADT Set is operations Set createEmptySet ( void ) 创建一个空集合。 int member(Set A,DataType x)
当x∈A时返回真值,否则取假值。
int insert(Set A,DataType x)
使x作为A的一个成员,如果x本来就是A的成员,则A不变。
6.3.2 抽象数据类型
假设用Dictionary表示抽象数据类型字典, 用DicElement表示字典元素类型,
用KeyType 来表示元素中关键码的类型,
用Position表示字典中元素的位置。
ADT Dictionary is operations Dictionary createEmptyDictionary ( void ) 创建一个空字典。 int search(Dictionary dic, KeyType key, Position p)
用位向量表示集合时,所占空间的大小与公共超集的 大小n成正比,而与要表示的集合的大小无关。
array size 2
7
6
5
4
3
2
1 9
0 8
(a)位向量表示的存储结构示意图
array size 2
1
0
1
0
1
0
1 1
0 0
(b)集合 S={1,3,5,7,9} 的实际存储状态
算法实现
以位向量表示集合,只有两个集合都是某个公共 集合的子集时,它们互相运算才是有效的。由于 在位向量定义里并没有关于集合元素的实际信息, 只能要求参与运算的两个位向量长度相同。
int delete(Set A,DataType x) 将x从A中删除,如果x本来就不在A中,则不改变A。 int union(Set A,Set B,Set C) 求集合A和B的并集,结果在集合C中。 int intersection (Set A,Set B,Set C)
求集合A和B的交集,结果在集合C中。
位向量表示集合的存储结构:
typedef struct {
int size; /*字符数组的长度*/
/*位向量空间。每一数组元素保存8位。*/
char * array;
} BitSet;
下图给出了一个公共超集是从0到9的整数集合,采用 位向量表示的存储结构示意图。 从图中可以看出每个整数所对应的二进制位的位置。 当集合S={1,3,5,7,9}时,它的实际存储状态如图(b)所 示(注意其中元素的排列方法)。