为什么要用散列表(哈希表,hashtable)

Hash表不是直接直接把关键字作为数组下标,而是根据关键字计算出下标。-------算法导论

       数组是一种支持直接访问的数据结构,使用确定的位置来存储和检索数据,十分高效。对数组操作时,隐含的一个动作是通过 特定的规律来确定下标。例如一张图片像素所组成的二维数组中,通过行数a和列数b可以得到二维下标(a-1,b-1)。

       大家对于数列都很熟悉,等比数列,等差数列等都是常用到的数列形式。数组下标本身就是一种数列,只不过这是最简单的顺序递增:“1,2,3,4…”。有一类智力题,是看序列找规律,预测下一个,从逻辑的角度来讲,只要你能自圆其说下一个是什么都有可能(有兴趣可以去看看-电影-牛津大学谋杀案)。而一组随机给出的数列起始位,也是可以预测之后数列的发展,只不过其中的规律特别复杂罢了。实际上寻找的是特征到位置的映射关系

      如果给出一个输入值的集合,包含很多元素,能否按照各个元素的特征找到映射规律使其存放到顺序(存储位置顺序)的数组中呢?Hashtable就是用来解决这个问题的。

      对于集合Arr = {23,7,9,1,10},如何才能建立一个快速的映射关系呢?最简单的方式就是取大小为max(Arr(0),Arr(1),…Arr(n))一个数组,将其存储到对应的位置上,隐含的操作是value mod max(valueSet),为了存储五个元素,花费了23个存储位置,这显然有些浪费。可不可以让它们的存储得更紧凑一些呢,可以使用mod运算很方便的达到这一点:使用value mod 5,将得到{23,7,9,1,10} -> {3,2,4,1,0},这样我们就可以使用5个位置来存储了。当然数组是我特意挑选的,mod也不是唯一的映射方法,这里我们可以看到散列的一个优点将一个大的输入值域,映射到小的输出值域上来,节省空间。

       另外一种适用Hashmap的场景是,不能直接获得下标值的情况。例如集合中的元素是文件或者字符串,通过映射,获取hash值确定存储位置(同时达到映射到小集合的目的)。

                         

        Hash映射的关系如图所示,注意以下几点:

  1. 在完成hash映射之前的集合A的值域一般大于和等于集合B的值域的,但是并不强制。
  2. 集合A本身的元素个数并不等于其值域,一般要进行预去重处理。
  3. 集合A的值域有可能是有限的也有可能是无限的,例如正有理数->向下取整->整数。
  4. 集合B必定有有限的。
  5. Hashmap一般只支持Insert,Search,Delete这三种操作,因此十分高效,操作的时间复杂度为O(1)。

实际的场景要复杂一点,大集合到小集合的映射是有碰撞的风险的。怎样降低这样的风险?碰撞发生了怎样处理呢?后续的章节会讨论着两个问题。

你可能感兴趣的:(数据结构)