的形式有所不同。下面我们将介绍哈希函数的基本知识。
首先,哈希函数h的输入是一个哈希键值(hash-key ),输出是一个桶编号 (bucket number )。
假定桶的个数为整数B,则桶编号通常是0 到B-1 之间的整数。哈希键值可以是任何类型的数据。
哈希函数的一个直观性质是它们将哈希键值“随机化”( randomize)。更精确地说,如果哈希键
值随机地从某个合理的可能的哈希键分布中抽样而成,那么函数h 将会把数目近似相等的哈希键
值分配到每个桶中。这一点有可能做不到,比如当所有可能的哈希键值数目少于桶数目B时就是
如此。当然我们可以认为该总体不具有“合理”分布。然而,可能存在更细微的原因导致哈希函
数的结果不能近似均匀地分布。
例 假设所有的哈希键都是正整数。一个普遍且简单的哈希函数是h ( x) = x mod B,即x
除以B之后的余数。如果哈希键的总体是所有的正整数,那么上述哈希函数产生的结果会非常均
匀,即1/ B的整数将被分到每个桶中。但是,如果哈希键只能是偶数值,并且如果B=10,那么h(x )
的结果只能是0 、2 、4、6和8 ,也就是说,此时哈希函数的行为明显不够随机。另一方面,如果
选择B =11,那么会有1/11 的偶数会分到每个桶中,这时候哈希函数的效果又会很好。
对上例进行一般化,当哈希键都是整数时,如果选用一个与所有可能的哈希键(或者大部
分)都具有公因子的B时,将会导致分配到桶中的结果不随机。因此,通常都首选将B取为素数。
尽管这种情况下我们还必须要考虑所有的哈希键以B为因子的可能性,但是上述选择方法减少了
非随机行为的可能性。
如果哈希键不是整数,要如何处理呢?在某种意义上说,所有数据类型的值都由比特位组成,
而比特位序列常常可以解释成整数。但是,有一些简单的规则可以将通用的类型转化成整数。例
如,如果哈希键是字符串,那么可以将每个字符转换成其对应的ASCII码或Unicode码,每个码可
以解释为一个小整数。在除以B 之前可以将这些整数求和,只要B 小于字符串总体中各字节字符
码的典型求和结果,那么最后对B 取模的结果相对还是比较均匀的。如果B 更大,那么可以将字
符串拆分成多个组,每个组包含多个字符,一组字符可以连在一起看成一个整数。然后,将每组
字符对应的整数求和之后对B 取模。比如,如果B在10 亿上下或者说2
30,那么每四个字符合成一组对应一个32 位的整数,多个32 位整数的求和结果将会相当均匀地分配到10 亿个桶中去。
对于更复杂的数据类型,可以对上述字符串转化为整数的思路进行扩展来递归式处理。
对于记录型数据,记录中每个字段都有自己的类型,那么可以采用适合该类型的算法将
每个字段递归地转换成整数,然后将所有字段转换出的整数求和,最后对B取模来将整数
分配到不同桶中去。
对于数组型、集合型或包(bag)型
数据,数据中的每一个元素都是相同类型。可以先
将每个元素的值转换成整数,然后求和并对B取模。