此答案总结了TAoCP第3卷第6.4节的部分内容。
假设我们有一组值,其中要存储在大小为的数组中。我们使用哈希函数 ; 通常,。我们称的负载因子的。在这里,我们假设自然;在实际情况下,我们有,并且必须映射到自己。Ñ 甲米ħ :V → [ 0 .. 中号)中号« | V | α = nVnAmh:V→[0..M)M≪|V|甲米=中号米«中号米α=nmAm=Mm≪Mm
第一个观察结果是,即使具有统一的特征¹,两个具有相同哈希值的值的可能性也很高;这本质上是臭名昭著的生日悖论的一个例子。因此,我们通常将不得不处理冲突,并且可以放弃最坏情况访问时间的希望。O(1 )hO(1)
但是,一般情况呢?让我们假设中的每个键都以相同的概率出现。平均检查条目数(成功搜索)。(搜索失败)取决于所使用的冲突解决方法。C S n C U n[0..M)CSnCUn
链式
每个数组条目都包含(指向其头部的)链接列表。这是个好主意,因为预期的列表长度很小()即使发生碰撞的可能性很高。最终,我们得到
Ç小号ñ ≈1+αnm
通过将列表(部分或全部)存储在表中,可以稍作改进。
CSn≈1+α2 and CUn≈1+α22.
线性探测
插入(重新搜索值),请
依次检查位置
h (v ),h (v )− 1 ,... ,0 ,m − 1 ,… ,h (v )+ 1直到空位置(resp 。v)中找到。优点是我们在本地工作,没有二级数据结构;但是,平均访问次数因α → 1而不同:
v
h(v),h(v)−1,…,0,m−1,…,h(v)+1
vα→1α<0.75CSn≈12(1+11−α) and CUn≈12(1+(11−α)2).
但是,
对于,性能可与chaining²相媲美。
α<0.75
双重散列
与线性探测类似,但搜索步长由与互质的第二个哈希函数控制。没有给出正式的推导,但是经验观察表明
此方法已由Brent修改;他的变体会通过更便宜的搜索来增加插入费用。Ç 小号Ñ ≈ 1M
CSn≈1αln(11−α) and CUn≈11−α.
请注意,从各个表中删除元素和扩展表的难度对于相应方法而言具有不同的难度。
最重要的是,您必须选择一种适合您的典型用例的实现。如果不总是保证,可以在预期的访问时间。根据所使用的方法,保持低很重要。您必须权衡(预期)访问时间与空间开销。很显然,一个好选择也很重要。α ħO(1)αh
1]由于任意愚蠢的无知程序员可能会提供,因此关于其质量的任何假设实际上都是一个难题。
2]请注意,这与使用Java的建议如何一致。h
Hashtable