【问题标题】:Hashmap Inserts O(N)?Hashmap 插入 O(N)?
【发布时间】:2013-06-26 22:05:13
【问题描述】:

所以,假设您有一个使用线性探测的哈希图。

您首先插入一个带有键 X 的值 X,它散列到位置 5,比如说。

然后,您使用键 Y 插入一个值 Y,该值也散列为 5。它将占用位置 6。

然后您插入一个带有键 Z 的值 Z,该值也散列为 5。它将占用位置 7。

然后你删除 Y,所以内存看起来像 "X, null, Z"

然后您尝试使用键 Z 插入一个值,它会检查 5,看到它已被占用,检查 6,然后将其插入为空。但是,已经有一个键为 Z 的条目,因此您将有两个键为 Z 的条目,这违反了不变量。

因此,在找到值本身之前,您是否不需要遍历整个地图。如果未找到,则可以将其插入第一个空空间。因此,不是所有对某个键的首次插入都是 O(N) 吗?

【问题讨论】:

标签: hashmap


【解决方案1】:

没有。

您遇到的问题是由于删除错误造成的。

事实上,使用线性探测从表中删除有些困难——以至于许多使用线性探测构建的表根本不支持删除。

也就是说:至少在理论上,哈希表上的几乎所有操作可能在最坏的情况下(插入、删除、查找等)最终都是线性的。无论哈希函数多么聪明你写的,有无限的输入可以散列到任何特定的输出。如果输入的选择非常不幸(或者只是一个糟糕的哈希函数),您最终可能会得到任意百分比的输入,所有这些都产生相同的哈希码。

编辑:如果您坚持使用线性探测支持删除,则基本思想是您需要确保每个条目“链”保持连续。因此,您对密钥进行哈希处理,然后从那里一直走到下一个空桶。您检查每个条目的哈希码,并用哈希到孔之前位置的最后一个连续项目填充“孔”。反过来,这可能会创建另一个洞,您必须用散列到您正在创建的洞之前的某个位置的最后一项来填充该洞(以此类推,递归地)。

【讨论】:

  • 所以要插入一个键,我不应该遍历列表,直到找到相同的键?似乎删除也应该遍历整个列表,直到找到键并删除条目,不是吗?
  • 是的,要插入密钥,您可能会一直走下去,直到找到一个空桶。我已经编辑了答案,以便更好地了解您如何处理删除。底线:是的,您几乎总是希望避免线性探测。
  • 啊,明白了,有道理。感谢您的帮助。
【解决方案2】:

不知道为什么村里的白痴 (;)) 删除了他的帖子,因为他是对的——过度提交/不平衡的哈希表会退化为线性搜索。

为了达到 O(1) 的性能,表不能过度使用(表必须足够大,给定条目数),并且哈希算法必须做得很好(避免不平衡),给定特征/统计的关键值。

需要注意的是,有两种基本的哈希表方案——线性探测,哈希同义词被简单地插入到下一个可用的表槽中,以及链表,哈希同义词被添加到表元素之外的链表中对于给定的哈希值。它们产生大致相同的统计数据,直到过度使用/不平衡,此时线性探测很快就完全崩溃了,而链表只是缓慢地退化。而且,正如其他人所说,线性探测使删除变得非常困难。

【讨论】:

  • 还有许多其他冲突解决方案,例如重新散列、二次散列、溢出区域或使用大于 1 的固定增量(通常是相对于表大小的质数)进行探测。这些对冲突链的最大胜利是它们消除了链表的指针,所以对于相同的总内存使用量,然后可以有更多的桶。
  • 是的,重新散列我在旧的 MS 库文件中遇到了 ca 1981 —— 这是线性散列的一个小变化。 (尽管在他们的实现中存在一个有趣的错误。)溢出区域只是链的一种变体。大多数情况下,这些方案似乎用于静态表,其中可以根据存储的特​​定数据“调整”参数。还有一些技术,例如可变大小的链元素(每个元素有几个条目),但概念没有太大变化。
猜你喜欢
  • 2021-09-09
  • 2012-12-19
  • 1970-01-01
  • 2021-12-08
  • 2021-04-24
  • 2011-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多