let insert key value =
internalArray[hash(key) % internalArray.Length].AddLast(key, value)
所以,如果我想从哈希表中检索一个项,我可以这样写:
let get key =
let linkedList = internalArray[hash(key) % internalArray.Length]
for (testKey, value) in linkedList
if (testKey = key) then return value
return null
Hans在下面的评论中给出了其他负载因子的实际公式,但对于指示值:对于负载因子1和加密强度哈希函数,1/e(~36.8%)的桶将趋于空,另外1/e(~36.8%)有一个元素,1/(2e)或~18.4%有两个元素,1/(3!e)约6.1%三个元素,1/(4!e)或~1.5%四个元素,1/(5!e) ~。3%有五个等。不管表中有多少个元素,非空桶的平均链长度都是~1.58(即是否有100个元素和100个桶,还是1亿个元素和1亿个桶),这就是为什么我们说查找/插入/擦除是< em > O < / em > (1)常量时间操作。
哈希表如何将键与值关联
给定一个如上所述的哈希表实现,我们可以想象创建一个值类型,例如' struct value {string name;int年龄;}; ',以及只查看' name '字段(忽略年龄)的相等比较和哈希函数,然后奇妙的事情发生了:我们可以在表中存储' {"sue", 63} '这样的' Value '记录,然后在不知道她的年龄的情况下搜索"sue",找到存储的值并恢复甚至更新她的年龄
-生日快乐,苏-有趣的是,它没有改变哈希值,所以不需要我们把苏的记录移动到另一个桶。
一旦我们有了哈希函数,我们就可以建立一个非常简单的哈希表。我们将创建一个“桶”数组;你可以把它想象成我们梳妆台里的抽屉。要在哈希表中存储一个项目,我们将计算该对象的哈希代码,并将其用作表中的索引,这类似于“选择该项目放在哪个抽屉中”。然后,我们把这个数据项放在桶内的那个索引处。如果桶是空的,那太好了!我们可以把物品放在那里。如果这个桶是满的,我们有一些选择我们可以做什么。一种简单的方法(称为< em > < >强链接哈希< /强> < / em >)是将每个桶视为一个项目列表,就像您的袜子抽屉可能存储多个袜子一样,然后将项目添加到该列表的索引处。
在开放寻址中,当像以前一样执行插入时,将跳转到某个槽,其索引依赖于计算的哈希码。如果那个位置是空的,那就太好了!你把东西放在那里,就完成了。但如果名额已经满了怎么办?在这种情况下,您可以使用一些辅助策略来找到一个不同的空闲槽来存储项目。最常用的策略是使用< em > < >强线性探测< /强> < / em >。在线性探测中,如果您想要的槽已经满了,则只需将其移到表中的下一个槽。如果那个槽是空的,那就太好了!你可以把物品放在那里。但是如果那个槽已经满了,你就移动到表中的下一个槽,等等(如果你到达了表的末端,就回到开始)。
另一个最近很流行的策略是< em > <强>杜鹃散列< /强> < / em >。我喜欢把布谷鸟杂音想象成《冰雪奇缘》。哈希表。不是只有一个哈希表和一个哈希函数,而是有两个哈希表和两个哈希函数。每一项可以恰好在两个位置中的一个——它要么在由第一个哈希函数给出的第一个表中的位置,要么在由第二个哈希函数给出的第二个表中的位置。这意味着查找是最坏的高效的,因为您只需要检查两个点来查看表中是否有内容。