学过编程语言的人,大多知道数组的概念,通过数组下标就可以访问到数组的元素,这里数组的下标是一种key,而此key的位置处存储的是所谓的卫星数据。我们希望能够在O(1)的时间里访问到某个key标识的卫星数据,数组在通常的情况下是一个不二的选择,数组的这种寻址方法学术上叫做直接寻址法,如何称之为“直接”呢?这里的直接指的是,依赖的key和存储的key本质上是一个东西,未经过映射和转换。那么如果key经过映射和转化,那么你已经在做散列了,也就是Hash。
开发寻址法有明显的限制,那就是key必须是整数,而且如果key分布的域较大的时候,安排数组时可能会浪费很大的地址空间。使用Hash能够,通过映射函数将key,不管是何种类型的key,只要选择合适的hash函数,总能将key映射到一个和数据量相当的一个范围中,这样在保持O(1)访问时间的同时也可以节省空间。但hash会碰到碰撞的问题,何为碰撞?
假设hash函数为y = h(k),如果两个不同的key:k1, k2, 他们的h(k1) = h(k2)时,就发生了碰撞。解决碰撞有两种方法:第一个是链接法,第二个是开放寻址法。
链接法就是在hash处构建一个链表,将所有的映射项都链接在相同的位置。
开放寻址法将hash函数进行了扩充,加入了一个探查序列:y = h(k, i), 构建Hash表的时候,只要按照i的序列探查各个hash槽,如果为空则找到位置并插入,查找的时候也是按照同样的探查序列进行查找。
开发寻址法的探查方法有三种:线性探查:h(k, i) = (hh(k) + i)mod m, 二次探查:h(k, i) = (hh(k) + ai + bi^2) mod m
双重散列:h(k, i) = (h1(k) + ih2(k)) mod m
下面介绍几个概念:
随机的选择散列函数的散列叫作全域散列,全域散列函数是一个散列函数集。
完全散列:在关键字集合静态的情况下,最坏期望的访问时间为O(1)的散列叫做完全散列,通常采用二级的散列方案,每一级上都是一个全域散列。