【问题标题】:How are HashMap et al really O(1)? [duplicate]HashMap 等人真的是 O(1) 吗? [复制]
【发布时间】:2013-10-05 18:57:54
【问题描述】:

我正在研究 Java 集合性能特征、Big O 表示法和复杂性等。有一个我无法理解的真实部分,这就是为什么 HashMap 和其他哈希容器被认为是 O(1),这应该意味着在 1,000 个条目的表中通过键查找条目应该与 1,000,000 个条目的表所用的时间大致相同。

假设你有一个 HashMap myHashMap,用名字 + 姓氏的键存储。如果调用 myHashMap.get("FredFlinstone"),它如何能立即找到 Fred Flinstone 的 Person 对象?它怎么可能不必遍历存储在 HashMap 中的一组键来找到指向对象的指针?如果 HashMap 中有 1,000,000 个条目,则键列表也将是 1,000,000 长(假设没有冲突),即使它已排序,它也必须比 1.000 的列表花费更多的时间。那么 get() 或 containsKey() 时间怎么能不随 n 而变化呢?

注意:我认为我的问题会在Is a Java hashmap really O(1)? 中得到回答,但答案并没有真正解决这一点。我的问题也与碰撞无关。

【问题讨论】:

  • 他们不是真的。最坏的情况,他们仍然是O(n)
  • 顺便说一句,它不是您所说的键列表。它是一个数组,其中索引与对象的哈希码相关。
  • 您忘记了“HashMap”的“Hash”部分。你得到对象的哈希码,模 (%) 它是你的数组的大小"HashBuckets",然后一旦你在桶中,你就可以进行线性搜索。
  • 对于那些说我的问题重复的人,请阅读我帖子的最后一行,然后告诉我在那篇帖子的哪个位置回答了我的问题

标签: java performance hashmap big-o


【解决方案1】:

“我的问题也不是关于碰撞的。” - 实际上是间接的。无冲突 = O(1) ...

在最坏的情况下(病态的情况),会有一个桶,上面挂着N 的物品,然后是O(N)

【讨论】:

  • 嗯,这是我的观点的一部分。 O( )(与 theta 等相反)应该是最坏的情况。
【解决方案2】:

计算给定键的哈希函数需要固定时间。查找是否有存储到该键的值是随机访问操作 - 哈希图由数组支持。唯一的问题是确保具有相同值(哈希冲突)的不同键不会经常发生。如果它在 n 中发生一次,这对于平均情况下的恒定时间来说已经足够了。

【讨论】:

    【解决方案3】:

    让我们看一个非常简单的哈希映射和哈希函数示例。为简单起见,假设您的哈希映射有 10 个桶,并且它使用整数作为键。出于本示例的目的,我们将使用以下哈希函数:

    public int hash(int key) {
      return key % 10;
    }
    

    现在,当我们想在地图中存储一个条目时,我们对键进行哈希处理,得到一个 0-9 之间的整数,然后将该条目放入相应的存储桶中。然后,当我们需要查找一个键时,我们只需要计算它的哈希值,我们就可以准确地知道它在(或将在)哪个桶,而无需查看其他任何桶。

    【讨论】:

    • 这是有道理的,但是当键是字符串时会发生什么,就像在我的示例中一样?我知道 String 有一个 has hashCode,但可能的值是数百万。为了有用,必须有数千个具有数千个值的存储桶。一旦您进入正确的存储桶,您仍然会访问数千个密钥。那么我还缺少什么?
    • @dj_segfault 鉴于 hashCode 方法返回一个 int(并且通常只会返回一个正数),实际上大约有 20 亿 (2^31) 个不同的哈希码。该映射将该哈希码映射到特定的存储桶(例如,通过修改存储桶的数量)。两个键碰撞的几率是地图大小的函数。只要您的地图相对于您希望放入其中的对象数量足够大,碰撞将非常罕见。
    • 好的,我想我们已经到了让我感到困惑的地步了。感谢您的耐心等待。因此,如果有大约 2B 个可能的代码,为了在一跳中找到一个密钥,您将需要 2B 个桶,对吗?如果你有 100K 个包含 1K 个项目的存储桶,一旦你使用模数技巧跳到正确的存储桶,你仍然会通过 1K 个项目来找到匹配项
    • 您假设所有存储桶都已满。如果您真的想在一张地图中存储数十亿个对象,那么您肯定会遇到一些性能问题。如果你想存储 n 个字符串并且你有一个包含 n*2 到 n*3 个桶的映射,那么每个桶几乎永远不会有 > 1 个项目。
    • 很抱歉延迟接受您的回答。我想先和一些人讨论一下,以确保我真的理解它。
    猜你喜欢
    • 2010-11-06
    • 2013-12-26
    • 2021-12-18
    • 1970-01-01
    • 2019-07-30
    • 2019-07-27
    • 1970-01-01
    • 2016-09-04
    相关资源
    最近更新 更多