我正在尝试理解哈希表中的开放寻址,但有一个问题在我的文献中没有得到解答。它涉及如果使用二次探测则删除这种哈希表中的元素。然后将被移除的元素替换为哨兵元素。然后get()操作知道它必须更进一步,add()方法将覆盖它找到的第一个sentinel。但是,如果我想添加一个元素,该元素的键已经在哈希表中但在探测路径中的哨兵后面会发生什么? add()方法将覆盖sentinel,而不是使用表中已有的相同键覆盖实例的值。然后我们在哈希表中有多个具有相同键的元素。我认为这是一个问题,因为它花费了内存,而且因为从哈希表中删除元素只会删除它们中的第一个,所以仍然可以在表中找到该元素(即它不被删除)。
因此,在替换sentinel元素之前,似乎有必要在整个探测路径中搜索要插入的元素的键。我忽略了什么吗?在实践中如何处理这个问题?
答案 0 :(得分:6)
但是如果我想添加一个带有键的元素会发生什么 已经在哈希表中,但在探测路径中的哨兵后面? 而不是用相同的密钥覆盖实例的值 已经在表中,add()方法将覆盖 定点。
add()
必须检查探测路径中的标记之后的每个元素,直到它找到一个空元素,如后面指出的那样。如果它在探测路径中找不到新元素并且上面有哨兵元素,它可以使用第一个哨兵槽来存储新元素。
http://www.algolist.net/Data_structures/Hash_table/Open_addressing(HashMap.java)上有一个哈希表实现。它的put()
方法就是这样做的。 (碰撞分辨率是参考片段中的线性探测,但我不认为这与算法的观点有重大区别。)
经过大量的删除操作后,表中可能会有太多的sentinel元素。对此的解决方案是偶尔重建哈希表(即重新散列所有内容)(基于项目数和前哨元素的数量)。此操作将消除哨兵元素。
另一种方法是在删除元素时从探测路径中删除sentinel(DELETED)元素。实际上,在这种情况下,表中没有哨兵元素;只有FREE和OCCUPIED插槽。这可能很贵。
所以似乎有必要搜索整个探测路径 在替换哨兵之前要插入的元素的关键字 元件。
是的,确实如此。你必须搜索,直到找到一个空元素。
这个问题在实践中如何处理?
我不太了解真实的哈希表实现。我想在开源项目中有很多可以在互联网上找到它们。我刚刚检查了Java中的Hashtable
和HashMap
类。两者都使用链接而不是开放寻址。
答案 1 :(得分:2)
对于迟到的回答感到抱歉,但Java有一个带有开放寻址的哈希表的示例:java.util.IdentityHashMap
。
此外,您可以使用GNU Trove Project。它的映射都是开放式寻址哈希表,如overview page所述。