文章目录
- 哈希表
-
- 哈希函数的构造方法
-
- 直接定址法
- 数字分析法
- 平方取中法
- 叠加法
- 除留余数法
- 伪随机数法
- 小结
- 处理冲突的方法
-
- 开放定址法
- 链地址法
- 再哈希
- 建立公共溢出区
- 哈希表的查找过程
哈希表 【Datastruct|哈希表 (Hash Table)】哈希表(Hash Table)又称杂凑表或散列表。其基本思想是:首先在在数据元素的关键字 k 和数据元素的存储位置 addr 之间建立一个对应关系 H,使得 addr = H(k),H 称为哈希函数。在建立哈希表时,把关键字为 k 的元素直接存入 H(k) 的单元中。以后当查找关键字为 k 的元素时,再利用哈希函数计算出该元素的存储地址 addr = H(k),从而达到按关键字直接存取元素的目的。关键字值不同的元素可能会得到相同的地址,即 k1 != k2,但 H(k1) = H(k2),这种现象称为冲突。实际应用中,冲突是不可避免的,只能通过改进哈希函数的性能来减少冲突。由此可见,哈希表的难点主要是构造哈希函数和处理冲突。
哈希函数的构造方法 所谓优雅的哈希函数,通常要追求构造方法的简单并且发生冲突的可能性小。即,能将给的的 key 均匀的散列到地址区间。
直接定址法
直接定址法的思想是:取关键字或关键字的某个线性函数值作为哈希地址,即 H(key) = key 或 H(key) = a * key + b ,其中 a、b 为常数。具体实现时为了使哈希地址与存储地址吻合可调整 a、b 的值。
直接定址法的特点是:地址集合和关键字集合的大小相同,即一个关键字对应一个存储地址,因此不会发生冲突,而且构造方法特别简单。但是在实际应用中能使用直接定址法的哈希函数的情况很少,这种方法只适用于关键字分布基本连续,且关键字集合较小的情况。
数字分析法
如果事先知道关键字的集合,并且每个关键字的位数比哈希表的地址码位数多时,可以从关键字中选出分布较均匀的若干位,构造哈希地址。
数字分析法适用于关键字是数字的情形,且可能出现的关键字均事先知道。
平方取中法
当无法确定关键字中哪几位分布比较均匀时,可以先求出关键字的平方值,然后按需要取平方值的中间几位作为哈希地址。这是因为,平方后中间几位和关键字中的每一位都相关,故不同的关键字会以较高的概率产生不同的哈希地址。
叠加法
叠加法是按哈希表的地址位数将关键字分成位数相等的几部分(最后一部分可以较短或舍弃),然后将这几部分相加,舍弃最高进位后的结果就是哈希地址。
具体实现方法有折叠法与移位法。折叠法是从一端向另一端沿分割界来回折叠,然后将各段相加。移位法是将分割后的每部分低位对齐相加。例如,key = 12345678901234,哈希表长 1000,则应把关键字分成 3 位一段,在此舍弃最低两位 34。折叠法求得的哈希地址 addr = 123 + 654 + 789 + 210。移位法求得的哈希地址 addr = 123 + 456 + 789 + 012。
除留余数法
取关键字被某个不大于哈希表长的数除后所得余数作为哈希地址。
例如,p 为小于等于表长的最大素数,则哈希函数 H(key) = key % p (其中 % 为求模运算)。为了尽可能地减少冲突,通常取 p 为不大于表长且最接近表长的素数,例如,表长为 1000 时,可取 p = 997。
伪随机数法
采用一个伪随机数作为哈希函数,即 H(key) = randdom(key)。
小结
哈希函数的选择,通常考虑以下五个因素:
- 计算哈希函数所需的时间
- 关键字的长度
- 哈希表的长度
- 关键字的分布
- 记录查找的频率
开放定址法
开放定地址法也称再散列法,其基本思想是:当关键字 key 的哈希地址 addr = H(key),出现冲突时,以 addr 为基础产生另一个哈希地址 addr1,如果 addr1 仍冲突,再以 addr1 为基础,产生另一个哈希地址 addr2,…,直到找到不冲突的哈希地址 addri,将相应的元素存入其中。
这种方法利用公式 addri = (H(key) + d[i]) % m 计算求得下一个地址,其中 H(key) 为哈希函数,m 为表长,d[i] 称为增量序列的第 i 个元素。增量序列的取值方式不同,相应的再散列方式也就不同。主要有以下几种方法:
- 线性探测再散列,d = {1, 2, 3, …, m-1},发生冲突时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。
- 二次探测再散列,d = {12,(-1)2, 2^2, (-2)^2, …, k^2, (-k)^2} (k <= m/2),发生冲突时,在表的左右进行跳跃式探索,比较灵活。
- 伪随机探测再散列,d = {伪随机数序列},具体实现时,应建立一个伪随机数发生器,并给定一个随机数作起点。
链地址法
链地址法的基本思想是:将所有关键字是同义词的元素连接成一条线性链表,并将其链头存在相应的哈希地址所指的存储单元中。因此,查找、插入和删除主要是在同义词链中执行。链地址法用于经常进行插入和删除的情况。
再哈希
再哈希的思想是:当发生冲突时,再用另一个哈希函数来计算下一个哈希地址,如果再发生冲突,再使用另一个哈希函数,直到不发生冲突。具体实现应预先设置一个哈希函数序列,序列中均为不同的哈希函数,在同义词产生地址冲突时,计算另一个哈希函数地址,直到冲突不再发生。
这种方法不易产生聚集,但增加了计算时间。
建立公共溢出区
建立公共溢出区的思想是:将哈希表分为基本表和溢出表两部分,凡是与基本表发生冲突的元素一律填入溢出表。
哈希表的查找过程 哈希表的查找过程与哈希表的创建过程基本一致,当查找关键字为 k 的元素时,首先计算 addr = H(k)。如果 addr 为空,则所查元素不存在,如果 addr 中的元素的关键字为 k,则找到查找元素,否则,按照构造哈希函数时解决冲突的方法,找出下一个哈希地址,直到哈希表中的某个位置为空或元素的关键字等于给定值为止。
推荐阅读
- 链表|ArrayList和LinkedList
- golang|GoLang之channel数据结构及阻塞、非阻塞操作、多路select
- LeetCode|K 次取反后最大化的数组和
- 7天带你全方位刷爆数据结构与算法,每天一道,高效刷题
- 数据结构|模拟浏览器操作程序(数据结构课设)
- 数据结构|背包问题求解(数据结构课设)
- mysql|Mysql高级学习笔记
- 数据结构|教学计划编制问题(数据结构课程设计)
- java|刷透近200道数据结构与算法,成功加冕“题王”,挤进梦中的字节