目录
1、集合
仅介绍用位向量实现集合抽象数据类型
- 当集合是全集合 { 0, 1, 2, …, n } 的一个子集,且 n 是不大的整数时,可用位(0, 1)向量来实现集合。
- 当全集合是由有限个可枚举的成员组成时,可建立全集合成员与整数 0, 1, 2, …的一一对应关系,用位向量来表示该集合的子集。
用带表头结点的有序链表表示集合
- 用有序链表来表示集合时,链表中的每个结点表示集合的一个成员。
- 各结点所表示的成员 e0, e1, …, en 在链表中按升序排列,即 e0 < e1 < … < en。
- 集合成员可以无限增加。因此,用有序链表可以表示无穷全集合的子集。
2、等价类
等价关系:自反、传递、对称
3、并查集
总体思路:
- 建立等价类的一种解决方案是先把每一个对象看作是一个单元素集合,然后按一定顺序将属于同一等价类的元素所在的集合合并。
- 在此过程中将反复地使用一个搜索(Find)运算,确定一个元素在哪一个集合中。
- 若两个等价对的元素不在同一个集合,则可以进行合并(Union)。
改进的方法
- 按树的结点个数合并
- 按树的高度合并
- 压缩元素的路径长度(在find操作中进行修改)
4、字典
字典是一些元素的集合,每个元素有一个称作关键码(key)的域,不同元素的关键码互不相同。
在讨论字典抽象数据类型时,把字典定义为<名字(Key)-属性(Attribute)>对的集合。
存储方式1:有序顺序表
有序顺序表中关键码从左到右依次增大。
顺序搜索的时间代价
折半搜索
每次的mid如果不对,下一次mid要去除。
练习:
具有12个元素的有序表,在等概率查找情况下,折半查找的平均查找长度为 。
答案:
解析:其实只要画一棵有12个元素的完全二叉树就行。
存储方式2:有序链表
与单链表基本相同。
5、散列表
基本思想:
- 理想的搜索方法是可以不经过比较,一次直接从字典中得到要搜索的元素。
- 建立一个元素存储位置Address与其关键码key之间的对应函数关系Hash() : Address = Hash(key)
- 在插入时依此函数计算存储位置并按此位置存放。在搜索时对元素的关键码进行同样的计算,把求得的函数值当做元素存储位置, 在结构中按此位置搜索。这就是散列方法。
冲突:
散列函数是一个压缩映象函数。关键码集合比散列表地址集合大得多。因此有可能经过散列函数的计算,把不同的关键码映射到同一个散列地址上,这就产生了冲突。
由于关键码集合比地址集合大得多, 冲突很难避免。所以对于散列方法, 需要讨论以下两个问题:
- 对于给定的一个关键码集合,选择一个计算简单且地址分布比较均匀的散列函数,避免或尽量减少冲突;
- 拟订解决冲突的方案。
散列函数多种多样,不再具体介绍;一下将具体介绍解决冲突的方案。
解决冲突:
处理冲突的闭散列方法
线性探查法 (Linear Probing)
成功与失败的平均搜索长度:
书上的例子体现了最多的细节,因此进行详细解释:
成功的情况:分母为被映射的元素的个数,分子为每个元素比较次数的总和。
失败的情况:分母为散列函数可能算出的所有地址的个数,分子为每个位置一直比较到空位置或最开始映射的位置的次数之和。
这个例子涉及到了多出的位置的计算:
从例子中可以看出第12个位置每次也要算的。
平方探查(Quadratic probing)
设H0 = hash(key), 一旦发生冲突,在表中顺次向后寻找下一个位置 d+1, d+𝟐^𝟐 , d+𝟑^𝟐 …
二次散列(Double Hashing)
设 hash1(key)=d , 当其地址d已经被其他元素占有了,则计算 hash2(key) =c, 在表中顺次检查相应的地址 d+c, d+2c, d+3c……。