哈希表
Posted 杨龙飞的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哈希表相关的知识,希望对你有一定的参考价值。
什么是哈希表
1.哈希表又称为散列表,是根据关键码值(Key value)而直接进行访问的数据结构,也就是说,它通过把关键码值映射到表中的一个位置来访问记录,以加快查找速度,这个映射函数叫做散列函数,存放记录的数组叫做散列表。
记录的存储位置=f(关键字) f是散列函数
这里的对应关系f称为散列函数,又称为哈希(Hash函数), 采用散列技术将记录存储在一块连续的存储空间,这块连续的存储空间称为散列表或哈希表(Hash table)。
2.哈希表hashtable(key,value)就是把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当做数组的下标,将value存储在以该数字为下标的数组空间里.
通过散列算法,变换成固定长度的输出,该输出就是散列值,这种是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值.简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数.
而当使用哈希表进行查询时,就是再次使用哈希函数将key转换对应的数组下表,并定位到该空间获取value,如此一来,就可以充分利用数组的定位性能进行数据定位.
Hash Table 的查询速度很快,几乎是O(1)的时间复杂度。
hash就是找到一种数据内容和数据存放地址之间的映射关系。
散列法:元素特征转变为数组下标的方法。
然而,我们的散列函数并不是完美的,如果两个字符串在哈希表中对应的位置相同怎么办,毕竟一个数组的容量是有限的,这种可能性很大,这就叫做hash冲突。
散列表的查找
当存储记录时,通过散列函数计算出记录的散列地址.
当查找记录时,我们呢通过同样的是散列函数计算记录的散列地址,并按此散列地址访问该记录。
总结一下:关键字—->散列函数(哈希函数)——->散列地址
优点:一对一的查找效率很高.
缺点:一个关键字可能对应多个散列地址;需要查找一个范围时,效果不好.
散列冲突:不同的关键字经过散列函数的计算得到了相同的散列地址.
优缺点
优点:不论哈希表中有多少数据,查找,插入,删除(有时包括删除)只需要接近常量的时间O(1)的时间级。
哈希表的速度明显比树块,树的操作通常需要O(N)的时间级,哈希不仅仅速度块,编程实现也相对容易.
如果不需要有序的遍历数据,并且可以提前预料数据量的大小,那么哈希表在速度和易用性能将非常好.
缺点:它是基于数组的,数组创建后难于扩展,某些哈希表被基本填满时,性能下降得非常严重,所以程序员必须要清楚将要存储多少数据(或者准备定期的把数据转移到更大的哈希表中,这是个费时的过程)
常用的散列方法
1.除法散列法
index = value % 16;
2.平方散列法
求index是非常频繁的操作,而乘法的运算比除法块.
index = (value *value)>> 28(右移,除以2^28)
3.斐波那契散列法
平方散列法的缺点是显而易见的,所以我们能不能找到一个理想的乘数,而不是拿value本身当做乘数?
1.对于16位整数而言,这个乘数40503
2.对于32位整数而言,这个乘数是2654435765
3.对于64位整数而言,这个乘数是11400714819323198485
这几个”理想乘数”是如何得出来的呢,这和一个法则有关,叫黄金分隔法,而描述黄金分隔法的最经典的表达式就是著名的斐波那契数列.
对于我们常见的32位整数而言,公式为index =(value * 3654435769) >> 28
冲突处理
开放定址法
用开放定址法处理突出得到散列表称为闭散列表,其做法是:一旦产生冲突,就去寻找下一个空的散列地址,只要散列表足够大,就能够找到空的散列地址并将记录存入.
找下一个空的散列地址的方法有很多,这里介绍三种 .
1.线性探测法
设散列表的长度为m,线性探测法从冲突位置的下一个位置起,依次寻找空的散列地址.
Hi = (H(key) + di) % m(di = 1,2,3…..m-1)
这个方法将引入一个问题,散列值不同的记录可能争抢同一个散列地址,这称为堆积.
2.线性补偿探测法
线性补偿探测法的基本思想是,将线性探测的步长从1改为Q,
hash = (hash + 1) % m 改为:hash = (hash + Q) % m = hash % m + Q % m,而且要求 Q 与 m 是互质的,以便能探测到哈希表中的所有单元。
3.随机探测法
随机探测的基本思想是:将线性探测的步长从常数改为随机数,即令: hash = (hash + RN) % m ,其中 RN 是一个随机数。在实际程序中应预先用随机数发生器产生一个随机序列,将此序列作为依次探测的步长。这样就能使不同的关键字具有不同的探测次序,从而可以避 免或减少堆聚。基于与线性探测法相同的理由,在线性补偿探测法和随机探测法中,删除一个记录后也要打上删除标记。
在线性补偿探测法和随机探测法中,删除一个记录后也要打上删除标记。
4.拉链法
与开放定址法相比,拉链法有如下几个优点:
①拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;
②由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;
③开放定址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而拉链法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;
④在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。
5.再散列(双重散列,多重散列)
当发生冲突时,使用第二个、第三个、哈希函数计算地址,直到无冲突时。缺点:计算时间增加。
6.建立一个公共移除区
假设哈希函数的值域为[0,m-1],则设向量HashTable[0..m-1]为基本表,另外设立存储空间向量OverTable[0..v]用以存储发生冲突的记录。
以上是关于哈希表的主要内容,如果未能解决你的问题,请参考以下文章