open live writer 测试

什么是Hash表

1.定义

Hash(散列/哈希),就是把任意长度的输入(又叫作预映射, pre-image),经过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间一般远小于输入的空间,不一样的输入可能会散列成相同的输出(引出后面碰撞处理)而不可能从散列值来惟一的肯定输入值。算法

数组的特色是:寻址容易,插入和删除困难;而链表的特色是:寻址困难,插入和删除容易。那么咱们能不能综合二者的特性,作出一种寻址容易,插入删除也容易的数据结构?答案是确定的,这就是咱们要提起的哈希表,哈希表有多种不一样的实现方法,我接下来解释的是最经常使用的一种方法——拉链法,咱们能够理解为“链表的数组”,如图:数组

                                                   clip_image001

这样的设计的数据结构须要考虑的最重要的问题就是,如何将数据存入?数据结构

2.散列法

元素特征转变为数组下标的方法就是散列法。散列法固然不止一种,下面列出三种比较经常使用的:函数

(1)除法散列法设计

最直观的一种,上图使用的就是这种散列法,公式:blog

index = value % 16ip

学过汇编的都知道,求模数实际上是经过一个除法运算获得的,因此叫“除法散列法”。ci

(2)平方散列法get

求index是很是频繁的操做,而乘法的运算要比除法来得省时(对如今的CPU来讲,估计咱们感受不出来),因此咱们考虑把除法换成乘法和一个位移操做。公式:hash

index = (value * value) >> 28 (右移,除以2^28。记法:左移变大,是乘。右移变小,是除。)

若是数值分配比较均匀的话这种方法能获得不错的结果,但我上面画的那个图的各个元素的值算出来的index都是0——很是失败。也许你还有个问题,value若是很大,value * value不会溢出吗?答案是会的,但咱们这个乘法不关心溢出,由于咱们根本不是为了获取相乘结果,而是为了获取index。

(3)斐波那契(Fibonacci)散列法

平方散列法的缺点是显而易见的,因此咱们能不能找出一个理想的乘数,而不是拿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 = (value * 2654435769) >> 28

若是用这种斐波那契散列法的话,那上面的图就变成这样了:

                                          clip_image002

3.基本原理及要点

hash函数 : 原始数据 ---(某些操做)----> 重复性小的int值 ----(散列函数)---->数组下标

碰撞处理(hash函数计算出的下标相同的状况)

一种是open hashing,也称为拉链法;另外一种就是closed hashing,也称开地址法,opened addressing。

相关文章
相关标签/搜索