在我的实现中,我使用了线性或二次探测的懒惰删除来解决碰撞问题。对于插入操作,当遇到一个已经被标记为懒惰删除的项时,我会用要插入的项替换它。这种做法的缺点或不正确之处是什么(无论是线性还是二次还是双重散列冲突解决)?难道这样做不能节省空间吗?
在我的实现中,我使用了线性或二次探测的懒惰删除来解决碰撞问题。对于插入操作,当遇到一个已经被标记为懒惰删除的项时,我会用要插入的项替换它。这种做法的缺点或不正确之处是什么(无论是线性还是二次还是双重散列冲突解决)?难道这样做不能节省空间吗?
在线性探测开放地址哈希表中,没有必要进行懒惰删除。硬删除可以在恒定时间内简单完成,而且不会导致表的退化。维基百科哈希表页面上多年来一直有它的伪代码。我不知道为什么现在没有了,但这里是一个永久链接,指向它曾经存在的地方:旧维基百科哈希表页面,为了方便起见,这里是伪代码:
function remove(key)
i := find_slot(key)
if slot[i] is unoccupied
return // key is not in the table
j := i
loop
j := (j+1) modulo num_slots
if slot[j] is unoccupied
exit loop
k := hash(slot[j].key) modulo num_slots
if (j > i and (k <= i or k > j)) or
(j < i and (k <= i and k > j)) (note 2)
slot[i] := slot[j]
i := j
mark slot[i] as unoccupied
该页面还有一个指向真实代码的引用。我相信这与插入具有完全相同的性能特征,并将表恢复到添加条目之前的状态。
这种删除方法比常用的“标记删除并偶尔重新哈希所有内容”更好,因为上述方法是常数时间,而不是平摊常数时间。如果您有一个包含一百万个项目的哈希表,并且要进行添加和删除,在“标记删除”方法中,偶尔的添加或删除将比之前和之后的操作慢一百万倍,这不是一个良好的性能特征。