常见的Hash函数解决冲突
在学习Hash函数的过程中,比较重要的一个点便是解决冲突的方法。虽然良好的Hash函数设计可以将数据尽可能的分散来使得冲突最小化,但在实际中,大部分的数据的内在规律是难以量化的,Hash函数不可避免的会出现数据存储时的冲突
经典的解决冲突的思想有以下几种
一、开放寻址法
开放寻址的基本思路即为——在存储值时若产生冲突,则根据特定探测规则寻找一个未被占用的地址进行存储。这样在读取数据时根据先前的探测规则便可以依照存储时的路线找到这个值。而探测规则的不同,造成存储结果的不同,主要有以下三种:
1、线性探测——即在产生冲突时访问当前地址+1的下一个地址,直到找到一个未被占用的地址。
2、二次探查——即依照
、
、
、
的步长来进行寻址,直到找到一个未被占用的地址。
3、伪随机——即每次的步长为随机数,直到找到一个未被占用的地址。
- 显然,线性探测的方法在越后面的寻址过程中会造成越来越多次的遍历,从而降低存储速度。
二、再Hash法
即通过构造多个不同的Hash函数,在产生冲突时使用另一个Hash函数来寻址。通过这样的方法可以根据数据的多个特点来设计不同纬度的Hash函数,从而使的数据不容易产生聚集。但多个Hash函数也使得数据的存储增加的时间。
三、链地址法
这种方法的思路是在表中不存储具体的数据而存储链表的头指针,从而使得每个地址都对应这一个链表,达到一个地址存储多个数据的效果。
四、溢出桶法
这个方法的思路类似于链地址法,在每个地址中建立溢出桶(缓冲区),从而将冲突的数据存入桶中。而具体的实现也有两种方式:可以为每一个地址建立独立的缓冲区,也可以为整个Hash表建立一个公共缓冲区,这样在访问数据时若对应的地址表未命中数据则表示数据存在对应的缓冲区中。
平均查找区间的计算
平均查找区间的定义为:
例如Hash函数为
采用线性探测的开放地址发,则数据集合{2,3,7,8}分别被存储在地址{2,3,4,5}中。
所以对于数据2与3只需要一次地址访问,而对于7则第一次访问地址2,发现未命中,根据线性探测规则依次访问3,4总共三次寻址,同理8也需要三次,故