我已经阅读了关于'Balls and Bins'问题的各种论文,似乎如果哈希函数正常工作(即它实际上是一个随机分布),那么如果我哈希,则以下应该/必须为真{1}}将值放入具有n
个插槽(或二进制位)的哈希表中:
n
而言为n
。1/e
。n/e
个球的概率为k
(已更正)。<= 1/ek!
(已更正)。这些看起来很容易检查。但<= ((e/k)**k)/e
测试(概率最大的碰撞次数)通常含糊不清。
大多数文本都声明任何bin中的最大碰撞数为max-load
。
有人说这是O( ln(n) / ln(ln(n)) )
。其他论文混合3*ln(n) / ln(ln(n))
和ln
- 通常没有定义它们,或者声明log
是基准e,然后在其他地方使用log
。
ln
是基于ln
或e
的日志,这个2
公式是正确的,max-load
应该有多大才能运行测试?< / p>
本讲座似乎是最好的,但我不是数学家。
http://pages.cs.wisc.edu/~shuchi/courses/787-F07/scribe-notes/lecture07.pdf
BTW,n
似乎意味着with high probability
。
答案 0 :(得分:2)
这是一篇引人入胜的论文/讲座 - 让我希望我参加了一些正式的算法课程。
我将根据我刚刚从中读到的内容,在这里尝试一些答案,并随时投票给我。我会欣赏一个修正,但不仅仅是一个downvote :)我也将在这里交替使用n和N,这在某些圈子里是一个很大的禁忌,但是因为我只是复制粘贴你的公式,我希望你能原谅我。
首先,日志的基础。这些数字以big-O表示法给出,而不是绝对公式。这意味着你正在寻找'大约ln(n)/ ln(ln(n))'的东西,而不是期望绝对答案,但更多的是当n变大时,n的关系最大碰撞次数应遵循该公式。你可以绘制的实际曲线的细节会因实现而异(我不太了解实际的实现,告诉你什么是'好'曲线,除了它应该遵循那个大O关系)。您发布的这两个公式实际上等同于big-O表示法。第二个公式中的3只是一个常数,与特定的实现有关。效率较低的实施将具有更大的常数。
考虑到这一点,我会进行实证检验,因为我是一名心脏病的生物学家,我接受过训练,以避免硬性证据作为世界实际运作方式的指示。从N开始作为某个数字,比如说100,然后找到其中碰撞次数最多的bin。那是你跑步的最大负荷。现在,您的示例应尽可能接近您希望实际用户使用的内容,因此您可能希望随机从字典或类似输入中提取单词。
多次运行该测试,至少30或40次。由于您使用的是随机数,您需要确保您获得的平均最大负载接近您的理论“期望值”。算法。期望只是平均值,但你仍然需要找到它,并且你的std dev / std关于那个平均值越严格,就越能说你的经验平均值与理论预期相符。一次运行是不够的,因为第二次运行(很可能)会给出不同的答案。
然后,增加N,比如1000,10000等。以对数方式增加它,因为你的公式是对数的。随着你的N增加,你的最大负荷应该增加ln(n)/ ln(ln(n))。如果它以3 * ln(n)/ ln(ln(n))的速率增加,那意味着你正在遵循他们在那次演讲中提出的理论。
这种实证测试也会告诉你你的方法崩溃的地方。可能是您的算法适用于N&lt; 1000万(或其他一些数字),但高于此,它开始崩溃。为什么会这样?也许你对代码中的32位有一些限制而没有意识到它(即使用'float'而不是'double'),或者其他一些实现细节。通过这些详细信息,您可以了解代码在实践中的效果,然后随着实际需求的变化,您可以修改算法。也许使算法适用于非常大的数据集使得它对于非常小的数据集非常低效,反之亦然,因此精确定位这种权衡将帮助您进一步表征如何使您的算法适应特定情况。永远是一项有用的技能。
编辑:证明为什么日志函数的基数与big-O表示法无关:
log N = log_10 (N) = log_b (N)/log_b (10)= (1/log_b(10)) * log_b(N)
1 / log_b(10)是常量,在big-O表示法中,常量被忽略。基础变化是免费的,这就是你在论文中遇到这种变化的原因。
答案 1 :(得分:2)
这是解决这个问题的粗略开始,涉及均匀分布和最大负荷。
人们(p)和门(d)将被用作名称,而不是箱子和球或骨灰盒或盒子或桶或m和n。
给定一定数量的人,每个门都有一个确切的预期值。例如,有5个人和5个门,预期的最大门正好比平均值(p / d)高1.2864 {(1429-625)/ 625},最小门正好是-0.9616 {(24-625)/ 625低于平均值。最高门与平均值的距离的绝对值比最小的门稍大,因为所有人都可以通过一扇门,但不少于零可以通过其中一扇门。由于人数众多(p / d> 3000),最高门与平均门和最低门之间距离的绝对值之间的差异可以忽略不计。
对于奇数个门,中心门基本上为零且不可伸缩,但所有其他门都可以从表示p = d的某些值进行扩展。 d = 5的这些舍入值是:
-1.163 -0.495 0 * 0.495 1.163 *从-0.12
慢慢接近零根据这些值,您可以计算通过5个门中每个门的任何人数的预期人数,包括最大门数。除了中间订购的门,与均值的差异可以通过sqrt(p / d)进行扩展。
因此,对于p = 50,000和d = 5:
通过最大门的预期人数,可能是5门中的任何一个,= 1.163 * sqrt(p / d)+ p / d。
= 1.163 * sqrt(10,000)+ 10,000 = 10,116.3
对于p / d < 3000,这个等式的结果必须略微增加。
随着越来越多的人,中间门从p = 100和d = 5的-0.11968慢慢变得越来越接近零。它总是可以四舍五入到零,就像其他4个门有很大差异一样。
6门的价值是: -1.272 -0.643 -0.202 0.202 0.643 1.272
对于1000门,近似值为: -3.25,-2.95,-2.79 ...... 2.79,2.95,3.25
对于任何d和p,每个订购门都有一个确切的预期值。希望存在良好的近似值(相对误差<1%)。一些教授或数学家必须知道。
为了测试统一分布,您需要一些平均有序会话(750-1000很好),而不是更多的人。无论如何,有效会话之间的差异都很大。这就是随机性的本质。碰撞是不可避免的。 *
5门和6门的预期值是通过使用640位整数的绝对强力计算并对相应的相对门的绝对值的收敛进行平均而获得的。 对于d = 5和p = 170: -6.63901 -2.95905 -0.119342 2.81054 6.90686 (27.36099 31.04095 33.880658 36.81054 40.90686) 对于d = 6和p = 108: -5.19024 -2.7711 -0.973979 0.734434 2.66716 5.53372 (12.80976 15.2289 17.026021 18.734434 20.66716 23.53372)
我希望您可以均匀地分发您的数据。
答案 2 :(得分:0)
经过一些研究和反复试验后,我想我可以提供一些回答的方法。
首先,如果您查看理论背后的数学,ln
和log
似乎会引用log base-e。但正如mmr指出的那样,对于O(...)估计,它并不重要。
max-load
可以根据您的喜好进行定义。使用的典型公式是
1-1 / N **ç
关于该主题的大多数论文都使用
1-1/n
一个例子可能是最简单的。
假设您有一个1000
个插槽的哈希表,并且您希望哈希1000
个东西。假设您还想知道max-load
,概率为1-1/1000
或0.999
。
max-load
是最终相同的哈希值的最大数量 - 即。冲突(假设您的哈希函数很好)。
使用公式获得准确k
个相同哈希值的概率
Pr[ exactly k ] = ((e/k)**k)/e
然后累计确切0..k
项的概率,直到总数等于或超过0.999
,告诉您k
是max-load
。
例如
Pr[0] = 0.37
Pr[1] = 0.37
Pr[2] = 0.18
Pr[3] = 0.061
Pr[4] = 0.015
Pr[5] = 0.003 // here, the cumulative total is 0.999
Pr[6] = 0.0005
Pr[7] = 0.00007
因此,在这种情况下,max-load
为5
。
因此,如果我的哈希函数在我的数据集上运行良好,那么我应该期望相同哈希值(或冲突)的最大数量为5
。
如果不是,则可能是由于以下原因:
您的数据具有较小的值(如短字符串),这些值会散列到相同的值。单个ASCII字符的任何散列都将选择128个散列值中的1个(有很多方法可以解决这个问题。例如,你可以使用多个散列函数,但是减慢散列速度并且我对此不太了解。)
< / LI>您的哈希函数不能很好地处理您的数据 - 请尝试使用随机数据。
您的哈希函数效果不佳。
我在问题中提到的其他测试也有助于查看您的哈希函数是否按预期运行。
顺便说一句,我的哈希函数很好用 - 除了短(1..4个字符)字符串。
我还实现了一个简单的分割表版本,它将哈希值放入2个位置中最少使用的插槽中。这使冲突数量增加了一半以上,这意味着添加和搜索哈希表的速度要慢一些。
我希望这会有所帮助。