哈希表删除中间元素后为什么要留下墓碑:机制演算第08例
用线性探测解决哈希冲突时,几个对象可能沿着同一条探测路径连续存放。删除中间项如果立即标成从未使用的空位,后面的对象可能再也查不到。
表长十一,编号除以十一的余数为起点,随后逐格前进并循环。查找遇到真正空位才停止,墓碑则继续;插入记住遇到的第一个墓碑,但仍要继续检查是否已存在相同编号,再决定落点。
本例的输入和输出
add为插入、remove为删除、find为查询。None为真正空位,负一为墓碑,其他数字为对象编号。
事件 | 检查位置顺序 | 结果 | 十一个槽位 ['add', 7] | [7] | 插入 | [None, None, None, None, None, None, None, 7, None, None, None] ['add', 18] | [7, 8] | 插入 | [None, None, None, None, None, None, None, 7, 18, None, None] ['add', 29] | [7, 8, 9] | 插入 | [None, None, None, None, None, None, None, 7, 18, 29, None] ['remove', 18] | [7, 8] | 删除 | [None, None, None, None, None, None, None, 7, -1, 29, None] ['find', 29] | [7, 8, 9] | 找到 | [None, None, None, None, None, None, None, 7, -1, 29, None] ['add', 40] | [7, 8, 9, 10] | 插入 | [None, None, None, None, None, None, None, 7, 40, 29, None] ['find', 40] | [7, 8] | 找到 | [None, None, None, None, None, None, None, 7, 40, 29, None] ['remove', 38] | [5] | 不存在 | [None, None, None, None, None, None, None, 7, 40, 29, None] ['add', 46] | [2] | 插入 | [None, None, 46, None, None, None, None, 7, 40, 29, None] ['find', 82] | [5] | 不存在 | [None, None, 46, None, None, None, None, 7, 40, 29, None] ['find', 82] | [5] | 不存在 | [None, None, 46, None, None, None, None, 7, 40, 29, None] ['find', 73] | [7, 8, 9, 10] | 不存在 | [None, None, 46, None, None, None, None, 7, 40, 29, None] ['find', 51] | [7, 8, 9, 10] | 不存在 | [None, None, 46, None, None, None, None, 7, 40, 29, None] ['remove', 77] | [0] | 不存在 | [None, None, 46, None, None, None, None, 7, 40, 29, None] ['add', 82] | [5] | 插入 | [None, None, 46, None, None, 82, None, 7, 40, 29, None] ['find', 51] | [7, 8, 9, 10] | 不存在 | [None, None, 46, None, None, 82, None, 7, 40, 29, None] ['add', 73] | [7, 8, 9, 10] | 插入 | [None, None, 46, None, None, 82, None, 7, 40, 29, 73] ['add', 46] | [2] | 已存在 | [None, None, 46, None, None, 82, None, 7, 40, 29, 73] ['add', 40] | [7, 8] | 已存在 | [None, None, 46, None, None, 82, None, 7, 40, 29, 73] ['add', 40] | [7, 8] | 已存在 | [None, None, 46, None, None, 82, None, 7, 40, 29, 73] ['find', 51] | [7, 8, 9, 10, 0] | 不存在 | [None, None, 46, None, None, 82, None, 7, 40, 29, 73]
表格中的编号只标识当前例子的元素,不应把对象身份、数组下标与计算数值混为一谈。阅读时先核对输入和边界,再沿记录检查每一步;空结果表示规则下没有可用项,并不是默认返回数值零。
复核与适用条件
墓碑不代表对象还存在,只代表这条探测链不能在这里提前结束。表格列出每次实际检查的位置、结果和完整表状态;满表没有空位或墓碑时插入失败,但已有对象的查找仍要正确。
这是一个固定容量、单线程的演算模型,没有扩容和并发写入。墓碑过多会让查找变长,实际实现可能需要整理或重建,但整理过程也必须保留所有真实对象及其查询结果。
练习时先独立复算一小段,再检查整体结果是否满足文中条件。遇到差异应保留中间记录并定位第一处不一致,而不是只调整最后答案。更换输入或操作规则后,需要重新计算,原记录只对这一例负责。