结论
- 如果哈希数据是均匀随机分布的,那么用质数和合数是没区别的。
- 但实际上哈希数据往往不是均匀分布的,比如存在很多等差数列(例如1,4,8,9,12,16,17这组数中就包含等差数列4,8,12,16)。
- 而这种情况使用合数会增加冲突概率,下面我会详细阐述原因。
先验知识
- 合数:指大于 1 的自然数,除了 1 和它本身以外,还有其他的正因数。
- 素数/质数:指大于 1 的自然数,除了 1 和它本身以外,没有其他的正因数。
- 哈希函数: H( c ) = c % N。
实验
- 这部分我们举例实际开发中可能存在的几组数据,然后将其分别映射到一个大小为素数7,一个大小为合数8的哈希表中,哈希函数采用上面提到的。
- 数据选择从1开始,一共十个元素的的等差数列,通过映射到不同大小的哈希表的冲突数量,体现效果。
数据1
(1,2,3,4,5,6,7,8,9,10)这组等差数据的差为1,从1开始。
哈希表大小为7(冲突数为3)
余数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | ||
7 | 8 | 9 | 10 |
哈希表大小为8(冲突数为2)
余数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | ||
8 | 9 | 10 |
数据2
(1,3,5,7,9,11,13,15,17,19)这组等差数据的差为2,从1开始。
哈希表大小为7(冲突数为3)
余数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
1 | 3 | 5 | |||||
7 | 9 | 11 | 13 | ||||
15 | 17 | 19 |
哈希表大小为8(冲突数为4)
余数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
1 | 3 | 5 | 7 | |||||
9 | 11 | 13 | 15 | |||||
17 | 19 |
结论分析
由上面的实验可以看到,哈希表的大小选择为偶数的时候,一旦数据中存在有规律的数据,其冲突的可能性将大大增加,数据分布不均匀。而素数大小的哈希表其冲突的情况比较均匀,即使数据有规律。因此很多用到哈希表的数据结构中为了保证程序的鲁棒性会选择用素数作为哈希表的大小。
原因分析
假设哈希表的大小为M,是一个偶数。当用M取模时,M的任意一个因子k, 都存在等差数列,其模空间会缩小为M/k, 从而增加冲突概率。 例如用8取模时,其因子4存在等差数列4, 8, 12,16…,这个数列的余数空间是(4,0,4,0,…) 。因此,取质数是最安全的选择,因为它的因子最少。