让哈希表的大小为静态(我设置一次)。我想根据条目数设置它。搜索产生的大小应该是素数并且等于2 * N(我猜的最接近的素数),其中N是条目数。
为简单起见,假设哈希表不接受任何新条目并且不会删除任何条目。
条目数量为200,2000,20000和2000000。
但是,将大小设置为2 * N对我来说似乎太过分了。它不是吗?为什么?如果是,那是我应该选择的尺寸?
我知道我们希望避免碰撞。我也明白,哈希表可能没有理想的大小,但我正在寻找一个起点。
我使用C而我想建立自己的结构,以便自我教育。
答案 0 :(得分:2)
大小应该是素数,等于2 * N(我猜的最接近素数),其中N是条目数。
肯定不应该 。可能这个建议意味着0.5的载荷因子是良好的权衡,至少在默认情况下是这样。
大小的素数是什么,取决于你选择的collision resolution algorithm。一些算法需要素数表大小(双重散列,二次散列),其他算法没有,并且它们可以受益于2的幂的表大小,因为它允许非常便宜的模运算。但是,当最近的"可用的表格大小"两次不同,哈希表的内存使用可能不可靠。因此,即使使用线性散列或单独链接,您也可以选择2大小的非幂。在这种情况下,反过来,选择特定的素数值是值得的,因为:
如果选择素数表大小(因为算法需要这个,或者因为你不满意2的幂大小所暗示的内存使用不可靠性),表格槽计算(按表大小模数)可以与散列相结合。有关详情,请参阅this answer。
当散列函数分布不好(来自Neil Coffey的答案)时,表2的幂大小是不可取的,这是不切实际的,因为即使你有糟糕的散列函数,avalanching它仍然使用电源切换到主表大小的-of-2大小会更快,因为在现代CPU上单个整数除法仍然较慢,因为良好的雪崩函数需要多个多重复用和移位操作,例如: G。来自MurmurHash3。
条目为200,2000,20000和2000000。
我不明白你的意思是什么。
但是,将大小设置为2 * N对我来说似乎太过分了。它不是吗?为什么?如果是,那是我应该选择的尺寸?
一般规则称为space-time tradeoff:为哈希表分配的内存越多,哈希表的运行速度就越快。 Here您可以找到一些图表说明这一点。所以,如果你认为通过分配表大小〜2 * N你会浪费内存,你可以自由选择较小的大小,但是准备好哈希表上的操作平均会变慢。
我知道我们希望避免碰撞。我也明白,哈希表可能没有理想的大小,但我正在寻找一个起点。
完全避免碰撞是不可能的(记住birthday paradox?:)碰撞的某些比例是一种普通情况。此比率仅影响平均运行速度,请参见上一节。
答案 1 :(得分:1)
您的问题的答案在某种程度上取决于您的哈希函数的质量。如果你有一个高质量的哈希函数(即平均值the bits of the hash code will be "distributed evenly"),那么:
首先,使用大量数据桶的建议本质上是一个帮助缓解散列函数不佳的情况的kludge。如果你有一个高质量的哈希函数,那么对于桶的数量本身确实存在任何约束并不清楚,并且一个常见的选择是使用2的幂,以便模数只是一个按位AND(尽管方式,现在并不重要)。一个好的哈希表实现将包括一个二级哈希来尝试和缓解原始哈希函数质量差的情况 - 请参阅Java的HashTable的源代码作为示例。
常见的加载因子是0.75(即每75个条目有100个桶)。这意味着大约50%的桶只有一个入口 - 所以它的性能很好 - 尽管它也浪费了一些空间。 “正确”的加载因子对您来说取决于您想要进行的时间/空间权衡。
在非常高性能的应用程序中,潜在的设计考虑因素也是如何在内存中实际组织结构/存储区以最大化CPU缓存性能。 (什么是“最佳”结构的答案基本上是“在您的数据实验中表现最佳的结构”。)