1、为什么出现哈希表?
之前学习的数据结构:栈、队列、数组、字符串以及树,都侧重于基于索引的查找,在进行数据的数值查找时,往往需要对部分甚至全部数据进行遍历,为了提升基于数据数值的查找,引入了哈希表。
2、哈希表的定义
哈希表又名散列表,是一种特殊的数据结构。
哈希表采用函数映射的设计,将数据的存储位置和数据本身关联起来。这种设计方式能够帮助我们快速定位到想要查找数值的数据(注:不需要进行额外的数值对比)。
公式:地址=f(数值)(f为函数)
3、哈希函数的设计方法
(1)直接定址法
哈希函数为关键字到地址的线性函数。如,H (key) = a*key + b。 这里,a 和 b 是设置好的常数。直接定址法适用于知道关键字的分布情况,查找表较小且连续的情况。
(2)数字分析法
如果关键字是位数较多的数字(比如手机号),且这些数字部分存在相同规律则可以采用抽取剩余不同规律部分作为散列地址。数据分析法适合处理关键字位数比较大的情况。例如手机号的存储。
(3)平方取中法
选取关键字的平方,然后根据可使用空间的大小,选择平方数的中间几位为哈希函数。平方取中法适合于不知道关键字分布且位数又不是很大的情况。
例:1)关键字1234的平方是1522756,取中间三位就是227。 2)关键字4321平方是18671041,取中间三位为671或710。
(4)折叠法
将关键字从左到右分割成位数相等的几部分(除最后一部分),然后将这几部分叠加切合,并按照散列表表长,取后几位作为散列地址。折叠法适用于关键字位数较多的情况。
例:散列表表长为0~999,地址位数为3位,我们将关键字9876543210分为四组,987|654|321|0,然后这几部分求和987+654+321+0=1962,取后3位962即为散列地址。
(5)除留余数法
将关键字或关键字折叠后、平房取中后对某个数取模,对于散列表表长为m的散列函数公式为:H(key)=key mod p(p<=m)。
储留余数法最重要的就是p的选择,直接影响冲突个数。一般的,p为小于等于m(最接近m)的质数。
哈希函数的设计原则就是尽量减少哈希冲突,使元素均匀的分布在各个位置上。
4、哈希冲突
我们将通过哈希函数映射到同一位置的情况称之为哈希冲突。
常见的处理冲突的方法如下:
1、开放定址法
开放定址法:一旦发生冲突,寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能够找到,并将记录存入。
(1)线性探测再散列
(key)=(f(key)+di) mod m(di=1,2,3...m-1)。当发生冲突时,向下逐个查找,直到找到一个空地址。缺点:关键字堆积严重,效率较低。
(2)二次探测再散列
f(key)=(f(key)+di) mod m(di=1²,-1²,2²,-2²,...,q²,-q²,q<=m/2)。发生冲突时,向两侧双向查找,可避免关键字聚集在某一块区域。
(3)随机探测再散列
f(key)=(f(key)+di) mod m(di是一个随机数列)。di是伪随机数,通过随即种子产生。
2、再散列函数法
事先准备多个散列函数,冲突发生时,就更换一个散列函数重新计算散列地址。fi(key)=RHi(key)(i=1,2,...k)。
3、链地址法
将所有关键字为同义词的记录存储在一个单链表中。链地址法不会出现找不到地址的情况,同时,在查找时需要遍历单链表,带来了一定的性能损耗。
5、哈希表的基本操作
给定key值,通过哈希函数计算出哈希地址。
如果哈希地址对应的值为空,则查找不成功。
反之,则查找成功。