简析模余法中哈希表长度为何取素数

初学哈希表的时候可能会有一个错觉,就是在关键码一定的情况下,长度越大,哈希表的冲突概率应该越小。的确,当关键码在一个大范围内 ,比如0-1000, 完 全 随 机 \color{green}完全随机 分布的情况下,当我们把哈希表的长度从1开始递增,在这个过程中冲突的概率自然逐渐减小。

但是实际运用中,关键码的分布往往呈周期性。

在邓俊辉教授的《数据结构习题解析》第182页有这样一道习题:
在这里插入图片描述
邓公在解答中详细论述了发生冲突的原因,在此不再赘述。仅就其中画红圈部分的M/g发表一些自己的理解:

首先仔细审题,一共有M个(也就是散列表长度)关键码,这说明关键码的取值范围大概是0~M*T。
其次观察在这里插入图片描述
图中与05冲突的散列码:29、53、77
对于其中任意一个,比如29来说,有 5%12 == 29 % 12,即 5 % 12 == (5 + 8 + 8 + 8) % 12,不难观察到,(8+8+8)% 12 = 0。即3 * 8 % 12 == 0,这里8是周期T,12是表长M,记3为k,要找有多少个关键码在这一点(05)冲突即是找有多少个k使k * T % M == 0成立

问题进行到这里,先暂停一下,看另外一个问题。
  要使a * b % c == 0,abc三个数字应该满足什么条件?
  首先对a、b进行因式分解:
  a = a1 * a2 * a3…  b = b1 * b2 * b3…
  然后将a的部分因子跟b的部分因子凑出来一个相乘得c的式子,如果能
  凑出来,那么a * b % c == 0这个等式就成立,反之,不成立。
  例如:3*8 % 12 = 3 * (2 * 2 * 2) % 12 = (3 * 2 * 2) * 2 %12
  显然等于0

好了回到刚才的问题,有多少个k使k * T % M == 0成立
令g = gcd(M, T)。
如果T凑出的一个因子是g,那k只需要凑出一个M/g即可。那么符合这个条件的k有哪些的?没错就是(M/g, 2M/g, 3M/g…) 那总共有几个这样的k呢? M/(M/g) = g个。
那么如果T凑出的因子小于g呢?不妨设为Tg,(此时有Tg < g) 不难验证(然而还是稍微有一点难度)g是Tg的整数倍。那么符合这个条件的k有哪些呢?(M/Tg, 2M/Tg, 3M/Tg…)那这时有多少k呢?M/(M/Tg) = Tg个。同样不难验证,这个范围是(M/g, 2M/g, 3M/g…)的一个真子集。
要使这样一个k的取值范围尽量小,那么就应该使T和M的最大公约数尽可能的小。如果M和T互质,最大公约数为1,此时k只能取(M/1, 2M/1, 3M/1…),即M的倍数,才会使等式成立。

所以要想冲突率降低,只需M和T的最大公约数尽可能的小,即M为素数。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值