数据结构笔记(第六章)

第六章 集合与字典

这部分只讲了散列

散列表

词典(Dictionary)的抽象数据类型

在计算科学中把词典当作一种抽象数据类型。
在讨论词典抽象数据类型时,把词典定义为 <名字-属性>对的集合。

一、基本概念

若能在待查记录的关键字值和它的存储位置之间建立一个确定的对应关系f,则查找时不必再进行关键字值间的比较。这个对应关系f 称为哈希(Hash)函数, 按这个思想建立的表为哈希表(也称散列表).

哈希方法(建表与查找)
选取某个函数,依该函数按关键字计算元素的存储位置,并按此存放;查找时,由同一个函数对给定值k计算地址,将k与地址单元中元素关键码进行比较,确定查找是否成功。
冲突
通常关键码的集合比哈希地址集合大得多,因而经过哈希函数变换后,可能将不同的关键码映射到同一个哈希地址上,这种现象称为冲突。

所以对于散列方法, 需要讨论以下两个问题:
1)构造好的哈希函数
(a)所选函数尽可能简单,以便提高转换速度;
(b)所选函数对关键码计算出的地址,应在哈希地址集中大致均匀分布,以减少空间浪费。

2)制定一个好的解决冲突的方案
查找时,如果从哈希函数计算出的地址中查不到关键码,则应当依据解决冲突的规则,有规律地查询其它相关单元。

二、构造哈希函数的基本方法

基本要求

设关键字集K中有n个关键字,哈希表长为m,即哈希表地址集为[0,m-1],则哈希函数H应满足:

  1. 对任意ki∈K,i=1,2,…,n,有0≤H(ki)≤m-1;

  2. 对任意ki∈K,H(ki)取[0,m-1]中任一值的概率相等

常用哈希构造方法

直接定址法
除留余数法
乘余取整法
数字分析法
平方取中法
折叠法
随机数法

1直接定址法

举例

关键码集合为{100,300,500,700,800,900},选取哈希函数为Hash(key)=key/100,则存储结构(哈希表)如下:

此方法所得地址集合和关键字集合的大小相同,因此对于不同的关键字不会发生冲突,但实际中使用这种哈希函数的情况很少。

2除留余数法

取关键字被某个不大于哈希表表长 m 的数 p 除后所得余数为哈希地址。一般情况下, p≤m且为质数

举例

设有一组关键字如下:(19,14,23,01,68,20,84,27,55,11,10,79),试用除留余数法设计哈希函数

可取p为13,即令H(key)=key%13 。

为什么要对 p 加限制?

例:给定一组关键字为: 12, 39, 18, 24, 33, 21,若取 p=9, 则他们对应的哈希函数值将为: 3, 3, 0, 6, 6, 3

可见,若 p 中含质因子 3, 则所有含质因子 3 的关键字均映射到“3 的倍数”的地址上,从而增加了“冲突”的可能。

3、数字分析法

若关键字是r进制数,且可预知全部可能出现的关键字值,则可取关键字中若干位构成哈希地址。

举例

设要在长为100的哈希地址空间中保存80个数据元素,部分关键字值如下,试用数字分析法设计哈希函数

n数字分析法仅适用于事先明确知道表中所有关键码每一位数值的分布情况,它完全依赖于关键码集合。如果换一个关键码集合,选择哪几位要重新决定。

4、平方取中法

若关键字较短,则可先对关键字值求平方,然后取运算结果的中间几位为哈希地址

举例

  设某计算机语言中标识符定义为一个字母或一个字母加一个数字,又知字母、数字的机内码(以八进制数表示)如下:

  A:01 B:02 C:03 … Z:32

  0:60 1:61 2:62 … 9:71

现以标识符的机内码为关键字,构造哈希表,试用平方取中法设计哈希函数。

4、折叠法

将关键字值分割成位数相同的几个部分,然后取这几部分的叠加和(舍去进位)作为哈希地址。

移位叠加

  将各部分按最低位对齐,然后相加;

间界叠加

  将关键字值从一端向另一端沿分界线来回折迭,然后对齐相加。

举例

设某图书馆的馆藏图书不足10000种,现欲以国际标准图书编号为关键字构造哈希表,试用折叠法设计哈希函数。

移位叠加

设有编号:0-442-20586-4,即:0442205864,由低位向高位,每四位一折,可得三段,再将各部分按最低位对齐后相加,并舍去进位,即得对应的哈希地址。

间界叠加

设有编号:0-442-20586-4,即:0442205864,由低位向高位,每四位为一段,各段沿分割界来回折迭后对齐相加,舍去进位即得哈希地址。

一般当关键码的位数很多,而且关键码每一位上数字的分布大致比较均匀时,可用这种方法得到散列地址。以上介绍了几种常用的散列函数。在实际工作中应根据关键码的特点,选用适当的方法。有人曾用“轮盘赌”的统计分析方法对它们进行了模拟分析,结论是平方取中法最接近于“随机化”。

三、处理冲突的基本方法

处理冲突是指对于一个待插入哈希表的数据元素,若按给定的哈希函数求得的哈希地址已被占用,则按一定规则求下一哈希地址,如此重复,直至找到一个可用的地址以保存该元素。

开放定址法(开地址法)
链地址法(拉链法)
再哈希法(双哈希函数法)
建立一个公共溢出区

1、开放定址法

方法

令Hi=(H(key)+di)%m,i=1,2,…,m-1,其中H(key)为哈希函数,m为哈希表长,di为增量序列。

若取di=1,2,3,…,m-1,则称线性探测再散列;

若取di=12,-12,22,-22…,±k2,则称二次探测再散列;

若取di=伪随机数序列,则称伪随机探测再散列。

平方探查法是一种较好的处理冲突的方法,可以避免出现堆积问题。它的缺点是不能探查到哈希表上的所有单元,但至少能探查到一半单元。

举例
  设有一组关键字如下:(67,84,18,26,34,28),哈希函数为H(key)=key%7,用线性探测再散列法处理冲突,试画出哈希表存储结构示意图。

已知:

哈希函数:H(key)=key%7

有冲突时:Hi=(H(key)+di)%7 其中:di=1,2,3,4,5,6

线性探测法的优点:只要哈希表未被填满,保证能找到一个空地址单元存放有冲突的元素;
线性探测法的缺点:线性探测容易出现在相邻的哈希地址上“堆积”的问题。
解决方案:可采用二次探测法或伪随机探测法,以改善“堆积”问题。

二次探查法是一种较好的处理冲突的方法

优点:可以避免出现堆积问题。
缺点:不能探查到哈希表上的所有单元,但至少能探查到一半单元
可证明:当表长m为质数且表的装载因子不超过0.5时,新表项插入时,任何位置不会被探查两次。
注意二次探查表长 m 必为素数(质数)(如: 7, 11, 13,17,19, 23, … 等)。

散列表的装填因子=表中填入的记录数n/表长m

2、再哈希法(双哈希函数法)

Hi=RHi(key) i=1, 2, …,k
RHi均是不同的哈希函数,当产生冲突时就计算另一个哈希函数,直到冲突不再发生。
优点:不易产生聚集;
缺点:增加了计算时间。

3、链地址法(开散列)

将所有按给定的哈希函数求得的哈希地址相同的关键字存储在同一线性链表中,且使链表按关键字有序。

举例
设有一组关键字如下:(67,84,18,26,34,28),哈希函数为H(key)=key%7,用链地址法处理冲突,哈希表存储结构

哈希函数:H(key)=key%7 有冲突时:在对应链表中插入新结点

4、公共溢出区法

若关键字所对应的哈希地址已被占用,则保存到公共溢出区中。

设有一组关键字如下:(67,84,18,26,34,28),哈希函数为H(key)=key%7,用公共溢出区法处理冲突,试画出哈希表存储结构示意图。

哈希函数:H(key)=key%7

有冲突时:保存到公共溢出区

开散列和闭散列,这两种方法的不同之处在于:开散列法把发生冲突的关键码存储在散列表主表之外,而闭散列法把发生冲突的关键码存储在表中另一个槽内。

开散列法优于闭散列法;在散列函数中,用除留余数法作散列函数优于其它类型的散列函数,最差的是折叠法。

四、在哈希表中查找元素

在哈希表中查找数据元素的过程与将数据元素插入哈希表的过程基本一致,即:

根据待查关键字值,按给定的哈希函数,求哈希地址;

若该地址上无数据元素,则查找失败;

若该地址上有数据元素,则进行关键字值间的比较。若相等,则查找成功;若不等,则按冲突处理方法求下一可能的存储地址。

虽然哈希表在关键字值与存储位置间建立了映象,但由于冲突的存在,查找时仍需进行关键字之间的比较,因此仍以查找成功时的平均查找长度和查找不成功时的比较次数作为衡量查找效率的依据。

ASL succ=搜索到表中已有元素的平均探查次数
ASL unsucc=表中所有可能散列到的位置上要插入新元素时为找到空桶的探查次数的平均值。

哈希表的查找及分析

由于冲突的存在,哈希法仍需进行关键字比较, 因此仍需用平均查找长度来评价哈希法的查找性能。
哈希法中影响关键字比较次数的因素有三个:哈希函数处理冲突的方法以及哈希表的装填因子

哈希表的装填因子表明了表中的装满程度。越大,说明表越满,再插入新元素时发生冲突的可能性就越大。越小,发生冲突的可能就越小,而存储空间的利用率也就越低。
散列表的平均查找长度是装填因子α的函数,不直接依赖于 n 或 m。在很多情况下,散列表的空间都比查找集合大,此时虽然浪费了一定的空间,但换来的是查找效率。
不论表的长度有多大,总能选择一个合适的装填因子,以把平均查找长度限制在一定范围内。

posted @ 2020-06-16 16:54  繁辰一梦  阅读(626)  评论(0编辑  收藏  举报