前言:

当我们学习了数组和链表后,我们会发现数组的特点是:寻址容易,插入和删除困难;而链表的特点是:寻址困难,插入和删除容易。比如我们要找寻一个key对应的value,若用链表,时间复杂度为O(n),即使采用二叉排序树进行存储,也最多为O(logn)。但哈希表就能很好的将数组与链表的优点结合,从而达到查找的时间复杂度达到O(1),你不信???不信就来看看这种数据结构的强大之处。

哈希表:

Hash表就是采用了一个映射函数 f :key —> address 将key映射到该记录在表中的存储位置,从而在存储时,可以直接根据关键字和映射关系计算出该记录在表中的存储位置,然后在这个位置放入value,而在想要查找该记录时,可以直接根据关键字和映射关系计算出该记录在表中的存储位置,然后输出value。通常情况下,这种映射关系称作为Hash函数,而通过Hash函数和关键字计算出来的存储位置(注意这里的存储位置只是表中的存储位置,并不是实际的物理地址)称作为Hash地址。

hash函数:

1 直接定址法

取key的某个线性函数为Hash地址,即address(key)=a * key + b。如知道学生的学号从2000开始,最大为4000,则可以将address(key)=key-2000作为Hash地址。

2 平方取中法

对关键字进行平方运算,然后取结果的中间几位作为Hash地址。假如有以下关键字序列{421,423,436},平方之后的结果为{177241,178929,190096},那么可以取中间的两位数{72,89,00}作为Hash地址。

3 折叠法

将关键字拆分成几部分,然后将这几部分组合在一起,以特定的方式进行转化形成Hash地址。假如知道图书的ISBN号为8903-241-23,可以将address(key)=89+03+24+12+3作为Hash地址。

4 除留取余法

如果知道Hash表的最大长度为m,可以取不大于m的最大质数p,然后对关键字进行取余运算,address(key)= key % p。

在这里p的选取非常关键,p选择的好的话,能够最大程度地减少冲突,p一般取不大于m的最大质数。

5 斐波那契法

平方散列法的缺点是显而易见的,所以我们能不能找出一个理想的乘数,而不是拿value本身当作乘数呢?答案是肯定的。

1,对于16位整数而言,这个乘数是40503 
2,对于32位整数而言,这个乘数是2654435769 
3,对于64位整数而言,这个乘数是11400714819323198485

    这几个“理想乘数”是如何得出来的呢?这跟斐波那契数列有关。0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,…。   

对我们常见的32位整数而言,公式: 
            index = (key * 2654435769) >> 28

上面讲了几种hash函数的操作,那么当数据很多时,不免会出现address重复的情况,下面来看看hash解决冲突的方法:

1 开放定址法

       当一个关键字和另一个关键字发生冲突时,使用某种探测技术在Hash表中形成一个探测序列,然后沿着这个探测序列依次查找下去,当碰到一个空的单元时,则插入其中。比较常用的探测方法有线性探测法,比如有一组关键字{12,13,25,23,38,34,6,84,91},Hash表长为14,Hash函数为address(key)=key%11,当插入12,13,25时可以直接插入,而当插入23时,地址1被占用了,因此沿着地址1依次往下探测(探测步长可以根据情况而定),直到探测到地址4,发现为空,则将23插入其中。

2 链地址法

     采用数组和链表相结合的办法,将Hash地址相同的记录存储在一张线性表中,而每张表的表头的序号即为计算得到的Hash地址。如上述例子中,采用链地址法形成的Hash表存储表示为:

哈希表(hash table)

虽然能够采用一些办法去减少冲突,但是冲突是无法完全避免的。因此需要根据实际情况选取解决冲突的办法。

总结:

Hash表是一种特殊的数据结构,它同数组、链表以及二叉排序树等相比较有很明显的区别,它能够快速定位到想要查找的记录,而不是与表中存在的记录的关键字进行比较来进行查找。这个源于Hash表设计的特殊性,它采用了函数映射的思想将记录的存储位置与记录的关键字关联起来,从而能够很快速地进行查找。但hash表也有不足:它是基于数组的,数组创建后难于扩展,某些哈希表被基本填满时,性能下降得非常严重,所以程序员必须要清楚表中将要存储多少数据,或者准备好定期地把数据转移到更大的哈希表中,这是个费时的过程。

 

 

最后强烈推荐Coursera上普林斯顿大学的算法课点击打开链接

 

 

以上内容纯属个人学习总结,不代表任何团体或单位。若有理解不到之处请见谅!

 

 

分类:

技术点:

相关文章: