【问题标题】:Deletion time of items in a hashtables linked list哈希表链表中项目的删除时间
【发布时间】:2021-04-06 09:41:31
【问题描述】:

我目前正在阅读 CLRS 书籍并查看其中如何定义哈希表,在谈到开放哈希和使用链接解决冲突时,有一段文字如下:

If the hash table supports deletion, then its linked lists should be doubly linked
so that we can delete an item quickly. If the lists were only singly linked, then to
delete element x, we would first have to find x in the list T[h(x.key)] so that we
could update the next attribute of x’s predecessor. With singly linked lists, both
deletion and searching would have the same asymptotic running times.)

我不明白为什么会出现这种情况(或者更具体地说是如何),这不是一个问题,即当你知道元素加倍时为什么从链表中删除它会更快链表,我想我应该说清楚...

这与实际知道位置的方式有关,因此双向链表可以产生这种差异,因为查看哈希删除伪代码(如下),密钥用于生成导致正确的哈希可以找到链表的数组索引,但如何准确地将其转换为项目链表中的实际位置?

CHAINED-HASH-DELETE(T, x)
1 delete x from the list T[h(x.key)]

在我看来,仅对链接列表的键进行哈希处理,因此在任何一种情况下,仍需要搜索列表以找到当前正在删除的实际值?

我确定有一个简单的答案,但我不清楚!

【问题讨论】:

    标签: linked-list hashtable clrs


    【解决方案1】:

    在我看来,仅对链接列表的键进行哈希处理,因此在任何一种情况下,仍需要搜索列表以找到当前正在删除的实际值?

    没错,当有人询问erase(key) 时,双向链表没有任何好处,因为即使遍历单链表也很容易擦除。

    不过,像(伪代码)这样​​的代码还是很常见的......

    if (iterator i = hash_table.find(key)) {
        do_something_with(*i);
        if (should_erase(*i))
            erase(i);
    }
    

    这里,迭代器i可以是一个指向双向链表中一个节点的指针,因此每个解引用操作*i访问与该节点关联的元素/值都不必重复任何部分哈希表桶查找或双向链表搜索。

    如果它随后决定erase(i),则迭代器无需再次搜索即可识别要擦除的节点。

    如果你只使用单链表,那么erase(iterator) 为了避免重新搜索,它需要存储一个指向前一个元素的下一个指针的指针(这实际上是 GCC 的 C++ 哈希表容器所做的)。如果它只存储它(以保持迭代器更小),那么要访问迭代器逻辑寻址的元素,它必须首先查找前一个元素的下一个指针,然后跟随它到逻辑寻址的节点:这不是超级有效的。如果它存储了逻辑寻址元素的地址和前一个元素(或者更具体地说是它的下一个指针),那么迭代器就会变成更大的对象,也会对内存使用和性能产生潜在影响。尽管如此,您还是为列表中的每个链接保存了一个“上一个”指针,而且可能有很多元素而不是很多迭代器。

    【讨论】:

    • 你认为这就是他们在书中的意思吗?它只是描述删除过程本身,我完全得到你的答案,这是有道理的,但如果我们所做的只是从哈希表中调用删除对象,我不明白他们为什么建议链接列表将确保项目可以在恒定时间内删除,这意味着不需要搜索列表,但是以某种方式提供了指向实际项目的指针,并且可以更新 nextprevious,就像从双向链表中删除时一样。
    • “在恒定时间内删除,这意味着不需要搜索列表” - 删除发生在 amortised 恒定时间内 - O(1 ) - 因为这些列表的平均长度是恒定的,因为 1) 最大负载因子是恒定的(即,如果 #elements/#buckets 超过阈值,哈希表将调整大小,2) 跨桶的键分布应该是公平的甚至(请参阅我的回答 here 中的 Linked List Length Relates To Load Factor 了解一些统计信息)。总而言之,典型的列表长度不会随着 #elements 的增加而增加,因此没有大 O 影响。
    • 再次感谢,那么如果列表链接与否,那么在删除时是否真的有任何区别,正如他们所暗示的那样?我仍然认为,就像你的回答暗示(我认为)它不是。
    • 也就是说,您从 CLRS 引用的文本包含 “删除元素 x,我们首先必须在列表 T[h(x.key)] 中找到 x” - 它的措辞很糟糕,但是当他们在那里说“元素 x”时,他们并不是指元素按值(即具有应该找到和删除的键的独立元素对象),他们的意思是如果您有一个指向特定元素对象 x已存储在哈希表中的指针/引用/迭代器。我可以推断,因为我了解所涉及的操作,并且只有这样他们的段落的其余部分才是正确的,但措辞是积极误导和混淆的。
    • 其实现在我再看delete函数,你的解释清楚多了,当然已经有对节点的引用,因为它访问x.key,非常感谢你的解释和附加信息,这本书很难掌握,尤其是对于所谓的“温和介绍”,新年快乐!
    猜你喜欢
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 2013-09-17
    • 1970-01-01
    • 1970-01-01
    • 2017-07-17
    • 1970-01-01
    相关资源
    最近更新 更多