散列表(哈希表)

散列表的构造方法

没有什么方法对所有情况都是最好的,只有适合的才是最好的

直接定址法

直接定址法就是我们中学学习的函数y = f(x),散列表一般使用线性函数,即 f(x) = ax + b ,这种方法很简单,但是不常用

数字分析法

数字分析法需要根据具体的情况,抽取键中的某些值进行计算,比如电话号码,前三位是接入号,中间四位是归属地,最后四位才是用户编号,如果是统计一个地区的电话号码,可以只抽取后四位进行计算,数字分析法适合处理关键字位数比较大的情况,如果事先知道关键字的分布而且若干位分布较均匀.可以考虑使用这个方法

平方取中法

这个计算方法很简单,对关键字求平方,然后取出中间的几位作为散列地址,这种方法适合事先不知道关键字的分布,位数又不是很大

折叠法

折叠法是将关键字从左到右分割成等长的几部分,然后叠加求和,然后取最后几位作为散列地址,这种方法适合事先不知道关键字的分布,但关键字位数很长的情况

除留余数法

这个方法就是对关键字求模,对于散列表长度为m的情况,散列函数可以使 f(x) = x mod p (p <= m ),这个方法的关键在于p的值的确定,如果选的不好,那么会造成很多冲突,不过根据经验,一般p取小于m的最小质数或不包含小于20质因子的合数.这个方法最为常用

随机数法

顾名思义,就是选择关键字的随机数值作为散列地址,如果关键字长度不等时,采用这个方法比较合适

处理散列冲突

散列冲突 ,即key1 != key2,但是f(key1) = f(key2)的情况

开放地址法

所谓的开放地址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列列表足够大,总能找到
公式为 f(x) = ( f (x) + di ) mod m (di = 1,2,3,4... m-1)
这种方法只是开放地址的其中一种,叫做线性探测法,
还有一种就是二次探测法,公式是:
f (x) = ( f (x) + di ) mod m(di = 1^2 ,-1^2 , 2^2 , -2^2 ...q^2 , - q^2 ,q <= m /2 )
这种方法实现了双向探测,即如果原来的散列地址已经存在其他关键字,那么在这个地址的前后分别探测新的散列地址,
当然还有随机探测,公式和上面的很想,就是把 di 换成一个随机数
这个方法是常用的解决hash冲突的方法

再散列函数法

这种方法就是如果我们通过原来的散列函数计算得到的散列地址已经被占,那么对于这个关键字,我们使用另一种散列函数计算得到一个新的散列地址,以此类推

链地址法

这种方法就是如果计算得到的散列地址已经被占领,但是我就要这个位置,那怎么办,很简单,使用链表,将散列表每个位置都变成一个链表如果发生冲突,就加入到该散列地址位置的链表的首部即可.
我所知道的,Java的hashmap就是使用这种方法解决hash冲突的

公共溢出区法

这种方法就是将所有发生冲突而没出呆的关键字拿出来,找一个叫公共溢出区的地方,将它们放在哪里,在进行查找时,先在原先的散列表中进行查找,找到相应位置后进行比对,如果比对失败,再到公共溢出区进行查找.
这种方法在冲突数据很少的情况下,性能还是很好的.

散列表查找性能

  • 如果在没有冲突的情况下,散列表查找的时间复杂度是O(1),但是没有冲突的散列表只是理想中的,

猜你喜欢

转载自blog.csdn.net/qq_36865108/article/details/84710026