【问题标题】:Is HashTable/HashMap an array?HashTable/HashMap 是数组吗?
【发布时间】:2023-03-26 17:00:01
【问题描述】:

我对哈希感到困惑:

当我们使用Hashtable/HashMap(key,value)的时候,首先我知道内部数据结构是一个数组(已经分配在内存中)。

Java hashcode() 方法有一个 int 返回类型,所以我认为这个哈希值将用作数组的索引,在这种情况下,我们应该在 RAM 中的数组中有 2 个 32 次方条目,这不是实际发生了什么。

那么 Java 是否从范围较小的 hashcode() 中创建索引?

答案:

正如这些人在下面和文档中指出的那样:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/HashMap.java

HashMap 是一个数组。 hashcode() 再次重新散列,但仍然是整数,数组中的索引变为:h & (length-1);所以如果数组的长度是 2^n 那么我认为索引从重新散列值中获取第一个 n 位。

【问题讨论】:

  • 标准 Java API 没有 HashTable 类型。你的意思是Hashtable
  • @LewBloch 是哈希表
  • "在 java hashcode() 方法有一个 int 返回类型,所以理论上我们应该已经为 RAM 中的数组保留了 2 次方 32(即 4 个 Giga 条目)" - 我没有看到你的推理在这里。
  • @JonSkeet 嗨。请检查上面的更新。
  • 更新没有解释为什么你认为内部数组的大小首先必须是 2^32。您的“理论上如此”暗示了一个您没有解释的合乎逻辑的步骤(这是不正确的)。

标签: java hash hashmap hashtable


【解决方案1】:

Java HashMap 的结构不仅仅是一个数组。它是一个数组,但不是 2^31 条目(int 是有符号类型!),而是一些较小数量的桶,默认情况下最初是 16HashMap 的 Javadocs 解释了这一点。

当条目数超过容量的某个分数(“负载因子”)时,数组会增长到更大的大小。

数组的每个元素不只包含一个条目。数组的每个元素都包含一个条目结构(当前是红黑树,以前是列表)。该结构的每个条目都有一个哈希码,该哈希码在内部转换为数组中相同的桶位置。

您是否阅读过有关此类型的文档? http://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html

你真的应该。

【讨论】:

  • 谢谢刘。因此,如果 HashMap 使用的桶数小于 2^31,这意味着从 hashcode() 方法返回的 int 哈希值将再次重新哈希以适应范围,例如默认16,如有错误请指正?如果是这种情况,当前使用的将 int 哈希值重新散列为较小值的方法/算法是什么(是简单的模数)?
  • @MosabShaheen 为什么不直接阅读 HashMap 的文档和源代码?它是免费的,并且与您的 JDK 捆绑在一起。
  • @JBNizet 谢谢。 hashcode() 再次重新散列,但仍然是 int 并且数组中的索引变为:h & (length-1);所以如果数组的长度是 2^n 那么我认为索引从重新散列值中获取第一个 n 位。 grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
  • 这很合理,Lew +1
【解决方案2】:

通常,基本数据结构确实是一个数组。

需要找到一个条目(或在添加新对象的情况下为空间隙)的方法会将哈希码减少到适合数组大小的东西(通常通过模数),并将其用作索引进入那个数组。

当然,这增加了发生冲突的可能性,因为许多对象的哈希码可能会减少到相同的索引(无论如何都是可能的,因为多个对象可能具有完全相同的哈希码,但现在更有可能)。有不同的策略来处理这个问题,通常是使用类似链表的结构,或者如果匹配的第一个插槽被不相等的键占用,则选择另一个插槽的机制。

由于这会增加成本,因此这种冲突发生的次数越多,事情就会变得越慢,在更糟糕的情况下,查找实际上会是 O(n)(并且也会随着 O(n) 变慢)。

增加内部存储的大小通常会改善这一点,特别是如果它不是以前大小的倍数(因此减少哈希码以查找索引的操作不会导致一堆项目发生冲突在同一个索引上,然后再次给他们所有相同的索引)。在某些情况下(一定百分比、一定数量的与不具有相同完整哈希码的对象的冲突等),某些机制会在绝对必要之前(同时还有一些空白空间)增加内部大小。

这意味着除非哈希码非常糟糕(最明显的是,如果它们实际上完全相同),操作顺序保持在 O(1)。

【讨论】:

  • 感谢乔恩的回复。我们以 Java hashcode() 方法为例。此方法返回 int。这是否意味着 HashMap(将使用此方法)将在 RAM 中创建一个包含 2 次方 32 条目(4 Giga 条目)的数组。如果不是这样,为什么返回类型是 int,将其设为 byte/short 类型似乎更好。
  • 它会从较小的尺寸开始,但会根据需要变大。追求 40 亿个可能的值既可以提供较大的最大尺寸,也可以降低当模减小到较小的尺寸时,两个项目每次都保持碰撞的可能性。
  • 这很合理,乔恩 +1
猜你喜欢
  • 1970-01-01
  • 2016-07-07
  • 2010-11-15
  • 2020-10-11
  • 2015-12-20
  • 1970-01-01
  • 1970-01-01
  • 2016-11-12
  • 1970-01-01
相关资源
最近更新 更多