一个关于哈希函数的问题

Love AI 2009-06-03 09:46:43
使用除余法构造函数时,为什么选择一个大的质数作为除数效率比较高啊?
...全文
793 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
Love AI 2009-06-05
  • 打赏
  • 举报
回复
晕,到底应不应该取质数啊?
crst_zh 2009-06-05
  • 打赏
  • 举报
回复
Hash Table(哈希表)就是根据对象的特征进行定位的一种数据结构。一个简单的实现方法是将对象通过某种运算得到一个整数,再让这个整数除以哈希表的大小,取其余数,以此作为对象的存储位置。
很多的书上认为,哈希表的大小最好是选择一个大的质数,并且最好不要和2的整数幂接近。《算法导论》上还认为,最不好的选择是哈希表的大小恰好是2的整数幂,对此的解释是(只记得大意):因为计算机是用二进制存储的,当一个二进制数除以一个2的整数幂的时候,结果就是这个二进制数的后几位,前面的位都丢失了,也就意味着丢失了一部分信息,进而导致哈希表中的元素分布不均匀。
这个解释看似合理,但我不认同。不光是我,Java开发小组的人也不认同。Java里的HashSet类偏偏就把哈希表的大小设置成2的整数幂。可以设想一下,对于自然数集合中的任意一个数x,对于一个正整数M,难道x mod M为某些值的概率会大些吗?显然不是,因为x是在自然数集合里任选的,当选取的次数非常多时,x mod M的结果应该是平均分布在[0,M-1]中。我认为《算法导论》的错误在于先引入了二进制,其实二进制和哈希表的“碰撞”根本没有什么关系;然后说对除以2^n的余数会丢失位,丢失信息,这显然也不对,因为只要x>=M,x mod M的结果总是要“丢失一些信息的”。照《算法导论》的说法,如果计算机采用十进制,那哈希表的容量是10^n的话岂不是很糟?这种解释显然站不住脚。
我认为对于x mod M这样的哈希函数来说,好坏应该取决于x的生成方式和M的值。比如一个字符串“ABC”,如果我让x("ABC")=65*128^2+66*128+67,即把字符串当成一个128进制的整数,那么若M=128,那就很糟糕了。因为这样无论是什么字符串,最终结果只取决于最后一个字符,这才会造成分布不均匀。
crst_zh 2009-06-05
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 linyt 的回复:]
素数还是有一个很美丽,也很神奇的性质。
你看一下Jdk的源代码会发现,HashTable的桶的大小就是一个素数,当负载因子超过用户的指定值(default is 0.75)时,要扩大桶数,方法是原来桶数乘2再加1。

这里就涉及一个性质:素数的2倍加1后仍是素数。

数学真神奇……
[/Quote]

晕~~~~~~~~~~~,
7------素数
15-----是素数吗?
海枫 2009-06-05
  • 打赏
  • 举报
回复
素数还是有一个很美丽,也很神奇的性质。
你看一下Jdk的源代码会发现,HashTable的桶的大小就是一个素数,当负载因子超过用户的指定值(default is 0.75)时,要扩大桶数,方法是原来桶数乘2再加1。

这里就涉及一个性质:素数的2倍加1后仍是素数。

数学真神奇……
luxiaoxun 2009-06-04
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 crst_zh 的回复:]
关于取大数,是为了降低冲突,比如取100,那么求余的结果将在0-99之间分布,如果取5,那么求余结果只能在0-4之间分布。

关于取质数,这个还有争议,有人说2的幂次方更好,某些数据库就是采用这种方法的,感兴趣可以查一下。
[/Quote]

主要就是这两点,空间和解决冲突
crst_zh 2009-06-04
  • 打赏
  • 举报
回复
关于取大数,是为了降低冲突,比如取100,那么求余的结果将在0-99之间分布,如果取5,那么求余结果只能在0-4之间分布。

关于取质数,这个还有争议,有人说2的幂次方更好,某些数据库就是采用这种方法的,感兴趣可以查一下。
日光降临 2009-06-04
  • 打赏
  • 举报
回复

有两点:
1, 素数: 采用素数是为了处理key碰巧有某些不理想的性质, 比如若表的大小为10而key的个位都是0,则此时的10是一个非常不好的选择.
2, 大数: 采用适当大一点的数(比如,取表中元素个数的2倍)为将来解决冲突预留了空间,更简单,效率也更高.
ysysbaobei 2009-06-04
  • 打赏
  • 举报
回复
顶下
snail_1989 2009-06-03
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 xuexuankr 的回复:]
质数只能被自己和1整除,当有一个非质数A,被取模时,会遇到一种情况就是分子分母共有一个约数,约去那个数后,取模的范围就小了,相当于把原来设定的哈希范围缩小了,等于取了一个无法预期小的质数,增加了冲突的可能性。所以与其等着在哈希过程会出现不确定性的范围,不如干脆一点把哈希范围定大一点,并且不会出现哈希过程缩小容量的情况。
[/Quote]
xuexuankr 2009-06-03
  • 打赏
  • 举报
回复
质数在防冲突方面是个好东西。数学确实很有魅力
xuexuankr 2009-06-03
  • 打赏
  • 举报
回复
质数只能被自己和1整除,当有一个非质数A,被取模时,会遇到一种情况就是分子分母共有一个约数,约去那个数后,取模的范围就小了,相当于把原来设定的哈希范围缩小了,等于取了一个无法预期小的质数,增加了冲突的可能性。所以与其等着在哈希过程会出现不确定性的范围,不如干脆一点把哈希范围定大一点,并且不会出现哈希过程缩小容量的情况。
  • 打赏
  • 举报
回复
[Quote=引用楼主 JLU_Leven 的帖子:]
使用除余法构造函数时,为什么选择一个大的质数作为除数效率比较高啊?
[/Quote]

这个没什么感觉,可能在防冲突的算法里需要用到吧。
woods2001 2009-06-03
  • 打赏
  • 举报
回复
以前在严蔚敏的《数据结构》上看过··
是一种规律吧
好像还没被完全证明出来为什么是这样
后人拿这用吧~
雪碧爱可乐 2009-06-03
  • 打赏
  • 举报
回复
因为除法的使用次数比较少吧!

64,646

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧