散列表中使用素数作为表长的一点想法

昨天上数据结构课时,老师是这样解释为什么用除留余数法散列的散列表中使用素数作为表长的:

假设我们用偶数作为一个表的表长,然后我们往里面不断加入奇数,那么可以看到0,2,4...这些格子就被浪费了,而1,3,5...这些格子处就会有很大冲突。。。人们发现表长使用靠近需散列的数的总数的素数时效果最好。

我当时听完觉得奇怪,凭什么我要一直往里面加入奇数来专门看这种特殊情况下的散列态。如果一定要以特殊情况来考虑,什么表长的表散列效果都不会好,我只要不停往里面加入表长整数倍的数,就永远只有一个格子被用到了。(比如往表长13的散列表中添加13,26,39....)

后来查了一些资料,整理了一下现在自己大致的想法。参考了 https://blog.csdn.net/zhishengqianjun/article/details/79087525?ops_request_misc=&request_id=&biz_id=102&utm_term=%E6%95%A3%E5%88%97%E8%A1%A8%20%E7%B4%A0%E6%95%B0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-79087525 (讲的挺好)

首先散列需要的是将数据以尽可能减少冲突的方式放进表中。一般随机且平均分布的数,以除留余数的方法映射进散列表中时,性能都会好。这是很多文章中提到的,被散列数以间隔为1随机生成时,使用素数与非素数没区别的点所在。而以表长为间隔随机生成被散列数时,所有表冲突程度也是一般大。所以我们接下来需要考虑的是,被散列数呈现一定规律,但不至于极端的情况。

对于“表长使用靠近被散列数总数的素数”这一句话中,“靠近总数”和“素数”这两个关键词,我们探究“素数”这个点。当然靠近总数可以让所有需要被散列的数都进表,同时不大浪费又不需要扩容(这样看所选取的素数应该等于或略大于被散列数总数?)。我们可以很粗略地引进一个概念,就是由一个数及是其倍数的所有数组成的数列,我在这里把它叫做倍数列,2的倍数列,3的倍数列。。。想象每个数字都代表以它为基础的一串数列。由此我们可以比较好地看到为什么表长为非素数,即有除了1及他自身之外的因子会被评判为广义上的性能不够好。

比如以18作为表长,他有2,3,6,9几个因子。则当被散列的数 在2,3,6,9的倍数列中 有较集中出现 的现象时,以18作为表长冲突就会较大,我叫这些因子倍数列为冲突倍数列吧;而以19作为表长,由于19没有多余的因子,所以(1,19)中数的倍数列都不容易产生冲突。我们现在考虑随机生成若干列分别为m1,m2...(其中1<mi<表长)的倍数列,则可以看到若以18作为表长,则生成冲突倍数列的概率,高于若以19为表长生成冲突倍数列的概率,这个概率可以用 冲突倍数列数目除以(表长-2) 来大致的估计。(如16时,2,4,8均冲突,概率 3/14,而质数时概率均为0)

其实意思就是考虑了在position=x MOD M(表长)  这个除留余数的函数里,x含 平均生成的倍数列 这种较特殊情况。所以一些文章中说表长取什么数与x的生成方式有关,还有表长取2的幂次时有所谓性能最不理想的说法,因为可以看到在这种情况下冲突倍数列概率非常大。(因子倍数列即冲突倍数列:2,4,8...  以2的幂次为表长时,与表长设置大小相近的其他情况对比,它有因子且因子全是最小质数2,即因子倍数列在表长范围内分布最为密集)

以上只是上完课后的一些理解,不正确的或考虑不周的地方欢迎指正(有些句子比较长,就用了空格作为停顿~)。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值