【发布时间】:2021-10-15 05:16:56
【问题描述】:
如果我在 hashmap 中输入一个 key 和 value,并且基于 key hashcode 生成的索引大于 15,而 map 大小仍然小于阈值 12,会发生什么?
提前致谢。
【问题讨论】:
如果我在 hashmap 中输入一个 key 和 value,并且基于 key hashcode 生成的索引大于 15,而 map 大小仍然小于阈值 12,会发生什么?
提前致谢。
【问题讨论】:
HashMap 通常会对 hashCode() 方法提供的值执行模运算,以便将整数范围映射到其内部数组的有效索引范围内。
这可能会导致冲突(不同的哈希值映射到同一个索引),这是一个单独的主题,并且还会导致 HashMap 的 O(1) 预期时间的降级。需要注意的是,假设您的 hashCode() 实现是均匀分布的。
在良好的 HashMap API 中,您无需担心内部数组大小或冲突。这是由实现在内部以各种方式处理的。
在 Java 的 HashMap API 中没有公开可见的“阈值”。你能得到的最接近的是:
HashMap(int initialCapacity, float loadFactor)
这里,你提到的阈值相当于loadFactor。根据 Java 文档:
“作为一般规则,默认加载因子 (.75) 在时间和空间成本之间提供了很好的折衷。较高的值会减少空间开销但会增加查找成本(反映在 HashMap 类的大多数操作中,包括get和put)。在设置其初始容量时应考虑map中的预期条目数及其负载因子,以尽量减少rehash操作的次数。如果初始容量大于最大条目除以负载因子,将不会发生重新哈希操作。”
基本上这意味着如果 HashMap 中的冲突太多,它将扩大其当前数组大小并重新散列所有当前键,从而(希望)产生更均匀的分布。这应该具有在 HashMap 的一系列添加或删除中保持预期的 O(1) 复杂度的效果。
【讨论】:
让我给你一个更广泛的图片,而不是只关注 Java 的特定数据类型 HashMap,因为你的问题包括 hashcode 标签,在我看来,你对更通用的图片感兴趣 - 如何散列函数是否有效。
是你需要了解的。
通常,索引规范化如何发生完全取决于特定数据结构的实现,该数据结构将输入散列到键(如HashTable/HashMap)以及无论它是什么实现,可以肯定地说:
您的哈希函数 h(x) 应该负责始终且始终如一地生成一个整数,该整数位于后备数组的有效索引范围内。
在许多实现中,散列函数可能会返回一个很长的(并且可能是负数)整数,这通常由 index normalization 解决,它只是对该长整数(作物、使负数为正等)。
对于 Java 的 HashMap 实现,hashCode() 是:
@HotSpotIntrinsicCandidate
public native int hashCode();
这意味着,该实现被委托给底层。
但在大多数情况下,您可以假设它将使用后备数组长度的模(存储桶数),这意味着它永远不会超过该数组的长度(因此,您的哈希图的大小) .
【讨论】: