哈希表支持的一种最有效的检索方法:散列.
由于计算哈希值和在数组中进行索引都只消耗固定时间,因此哈希表的最大亮点在于他是一种运行时间在常量级的检索方法.
哈希表主要有两种:
1.链式哈希表:将数据存储在桶中的哈希表,每个桶里面都是一个链表,且链表的容量随着冲突的增大而增大.(换句话说就是如果有冲突,会在桶中的链表加上一个存储的值)
2.开地址哈希表:将数据存在表本身,而不是在桶中,他通过各种探查方法来避免冲突.
解决冲突:
不管在以上那种哈希表中,我们的目标是尽可能均匀的分配表中的元素.所以我们必须选择正确和哈希函数.
在链式哈希表中,哈希函数可以表示为:
h(k)=x
一般来说,大多数的散列方法都假设键值k为整数,所以,如果设置键值需要把传入的类型进行转换.
哈希函数可以使用:
取余法:
h(k)= k mod m (其中k表示转换后的整数,m表示哈希表的桶数)
比如:有m=11个位置,k为25,得到桶的索引index=25%11=3,所以在bucket[index]的位置存入值.
一般来说,需要避免m的值是2的幂,通常选择一个素数.
乘法:
h(k)= m(kA mod 1),
他将整数k乘以一个常数A(0<A<1),取结果的小数部分,然后乘以m取结果的整数部分.通常情况下,A取0.618,他是由√‾5减1除以2得到.
这个方法的有点是在取m得时候不需要啊那么慎重.
最后,如果还是有冲突的元素在一个桶内,哈希表会用链式结构存储冲突元素.
开地址哈希表
由于元素放在表本身,没有链式结构存储冲突元素,哈希表需要其他方法解决冲突.
线性探查:开地址哈希表中一种简单的探查方法就是探查表中的连续槽位.
表示为:如果存在i(0<i<m-1)
h(k,i)= (h‘(k)+i) mod m
其中h‘(k)可以使用上述的取余法.
大致步骤:
1.i=0,通过h‘(k)找到一个位置,如果位置没有元素,就存储元素.
2.如果有元素,i+1来查看这个位置的下个位置是否有元素.
3.循环1,2步骤.
这个方法的主要缺点是元素不能均匀散列.
双散列:
最有效的探查的方法,就是通过计算两个辅助哈希函数哈希编码的和来得到哈希编码.
表示为:如果存在i(0<i<m-1)
h(k,i)=(h1(k)+ih2(k)) mod m
h1和h2是两个辅助哈希函数.
一般来说:m的值取素数,然后令h1(k)= k mod m,h2(k)=1+(k mod m‘),其中m‘略小于m,一般取m‘=m-1或者m-2;
这种方法的优点是能在表中探查并产生较好的元素分布,缺点是必须限制m的值.这样才能保证在一系列探查中访问表中所有槽之后才会再次探查任何槽.