构造乘法散列表的乘法方法包含了两个步骤:
1. 用关键字 K 乘上常数 A (0<A<1),并抽取出 kA 的小数部分
2. 然后再用 m 乘以这个值,再向下去整
总之散列函数为:
h(k) = |_ (m*(k*Amod1)) _|
这里对m没有太大的要求,一般选择他为2的某个幂次方( m 的取值规定了hash的长度)
Knuth提出 A 的最佳选择为 A ≈ (√5-1)/2 = 0.618 033 988 7....
这里引出了我对这个 A 的值的思考。于是我写了程序来对 A 的选择做了测试。
首先我以 A={0, 0.01, 0.02 ...... 0.98, 0.99} 这些数字做了测试,并且m的取值为1000。
从而得出以下的结果:
Case 1000: a:0.010000 num:0 a:0.020000 num:49 a:0.030000 num:0 a:0.040000 num:74 a:0.050000 num:79 a:0.060000 num:50 a:0.070000 num:0 a:0.080000 num:74 a:0.090000 num:0 a:0.100000 num:89 a:0.110000 num:0 a:0.120000 num:74 a:0.130000 num:0 a:0.140000 num:49 a:0.150000 num:79 a:0.160000 num:74 a:0.170000 num:0 a:0.180000 num:50 a:0.190000 num:0 a:0.200000 num:95 a:0.210000 num:0 a:0.220000 num:50 a:0.230000 num:0 a:0.240000 num:75 a:0.250000 num:96 a:0.260000 num:50 a:0.270000 num:0 a:0.280000 num:75 a:0.290000 num:0 a:0.300000 num:90 a:0.310000 num:0 a:0.320000 num:75 a:0.330000 num:0 a:0.340000 num:50 a:0.350000 num:80 a:0.360000 num:75 a:0.370000 num:0 a:0.380000 num:50 a:0.390000 num:0 a:0.400000 num:95 a:0.410000 num:0 a:0.420000 num:50 a:0.430000 num:0 a:0.440000 num:75 a:0.450000 num:80 a:0.460000 num:50 a:0.470000 num:0 a:0.480000 num:75 a:0.490000 num:0 a:0.500000 num:98 a:0.510000 num:0 a:0.520000 num:75 a:0.530000 num:0 a:0.540000 num:50 a:0.550000 num:80 a:0.560000 num:75 a:0.570000 num:0 a:0.580000 num:50 a:0.590000 num:0 a:0.600000 num:95 a:0.610000 num:0 a:0.620000 num:50 a:0.630000 num:0 a:0.640000 num:75 a:0.650000 num:80 a:0.660000 num:50 a:0.670000 num:0 a:0.680000 num:75 a:0.690000 num:0 a:0.700000 num:90 a:0.710000 num:0 a:0.720000 num:75 a:0.730000 num:0 a:0.740000 num:50 a:0.750000 num:96 a:0.760000 num:75 a:0.770000 num:0 a:0.780000 num:50 a:0.790000 num:0 a:0.800000 num:95 a:0.810000 num:0 a:0.820000 num:50 a:0.830000 num:0 a:0.840000 num:75 a:0.850000 num:80 a:0.860000 num:50 a:0.870000 num:0 a:0.880000 num:75 a:0.890000 num:0 a:0.900000 num:90 a:0.910000 num:0 a:0.920000 num:75 a:0.930000 num:0 a:0.940000 num:50 a:0.950000 num:80 a:0.960000 num:75 a:0.970000 num:0 a:0.980000 num:50 a:0.990000 num:0
这里 hash 长度是1000,插入数字为 0~100, num 表示碰撞次数,可以看到一个明显的现象:对于a的末尾为奇数时,大部分均有很低的概率发生碰撞,而当为偶数的时候碰撞次数均很大,而且很多均是 50 或者是 75。
分析发现,这里和末尾那个偶数有关,因为这里是两位小数,乘数是10x 级,所以只要是偶数,当对 1 取模后就必然会和前面某个数重复。
例如:a = 0.22 时, k = 1 和 k = 51结果是一样的,均为 0.2 ,那么自然就会发生重复了。
之后我又进行更改,hash长度仍是 1000,但是插入数据也是1000个,即是全部插入,A 每次递增 0.001 结果发现在碰撞次数低的依旧很多
当我将A每次递增改为0.000 001 ,我等了10多分钟都没跑完。。。。最后强行终止了,打开文件后发现这里面碰撞次数低的依旧还是很多,由此可见,A值的选取方式是很多的,取黄金分割比只是一个建议~