hashmap是怎么解决hash冲突的?那他是怎么扩容的?

目录

hashmap是怎么解决hash冲突的?

hashmap的扩容机制


hashmap是怎么解决hash冲突的?

HashMap 使用的是哈希表数据结构,而解决哈希冲突的方法是链地址法(Chaining)。下面是 HashMap 如何解决哈希冲突的基本原理:

  1. 哈希表槽位

    HashMap 内部维护一个数组,这个数组的每个元素称为槽位(bucket)。槽位的数量通常大于或等于 HashMap 中的键值对数量,以确保散列的均匀性。槽位的索引是通过哈希函数计算得到的。

  2. 哈希函数

    当需要将键值对存储到 HashMap 中时,首先会计算键的哈希值。哈希值是一个整数,它代表了键在哈希表中的理论位置。哈希函数的目标是将不同的键映射到不同的槽位,但由于哈希函数的限制,可能会产生相同哈希值的情况,即哈希冲突。

  3. 链地址法

    当发生哈希冲突时,HashMap 采用链地址法。这意味着每个槽位不仅可以存储一个键值对,而且可以存储一个链表或红黑树等数据结构,用于存储冲突的键值对。

  4. 存储键值对

    当需要存储一个键值对时,HashMap 首先计算键的哈希值,然后根据哈希值选择一个槽位。如果槽位为空(没有冲突),则将键值对存储在该槽位上。如果槽位不为空(发生冲突),则将键值对添加到该槽位上的链表或树中。

  5. 查找键值对

    当需要查找一个键对应的值时,HashMap 首先计算键的哈希值,然后定位到槽位。然后,它会在该槽位上的链表或树中查找具有相同键的键值对。这个过程可以通过哈希值快速定位到槽位,然后在链表或树中进行线性查找或树搜索。

  6. 扩容

    HashMap 中的键值对数量超过一定阈值时,HashMap 会进行扩容,即增加槽位的数量。这是为了保持哈希表的性能,因为随着键值对数量的增加,槽位中链表或树的长度也可能增加,导致查找性能下降。

总结一下,HashMap 采用链地址法来解决哈希冲突,它使用哈希函数将键映射到槽位,每个槽位可以存储多个键值对。这种方法保持了 HashMap 的高效性能,即使在发生冲突的情况下也能够快速定位到槽位,然后进行查找或插入操作。当键值对数量增加时,HashMap 会进行自动扩容,以维持性能。

hashmap的扩容机制

HashMap 的扩容机制是为了在容量达到一定阈值时,自动调整槽位数量,以维持哈希表的性能。下面是 HashMap 的扩容机制的基本原理:

  1. 初始容量和加载因子

    当创建一个 HashMap 时,可以指定初始容量和加载因子。初始容量是哈希表的初始大小,加载因子是一个浮点数,表示哈希表何时需要进行扩容。加载因子默认为0.75,表示当哈希表中的键值对数量达到容量的75%时,就会触发扩容操作。

  2. 扩容触发条件

    HashMap 中的键值对数量超过了容量乘以加载因子的阈值时,就会触发扩容操作。例如,如果初始容量为16,加载因子为0.75,那么在键值对数量达到12个时,就会触发扩容。

  3. 扩容操作

    扩容操作涉及以下步骤:

    • 创建一个新的哈希表,其容量通常是原容量的两倍。
    • 遍历原哈希表中的每个槽位,将键值对重新分配到新的哈希表中。这个过程可能会导致键值对的重新哈希计算。
    • 释放原哈希表,以便垃圾回收。
  4. 重新哈希计算

    当扩容时,需要重新计算每个键的哈希值,以确定新的槽位位置。这是因为新哈希表的槽位数量不同,相同的哈希值可能会映射到不同的槽位上。重新哈希计算可以是一个相对昂贵的操作,但只需要在扩容时执行。

  5. 扩容的目的

    扩容的目的是减少哈希冲突,从而提高 HashMap 的性能。通过扩容,可以使槽位更加分散,减少链表或树的长度,从而在查找、插入和删除键值对时保持高效性能。

  6. 性能和容量的选择

    选择适当的初始容量和加载因子对 HashMap 的性能非常重要。如果容量设置得太小,可能会导致频繁的扩容操作,影响性能。如果容量设置得太大,可能会浪费内存。通常,根据数据量的估计,选择一个适当的初始容量和加载因子。

总的来说,HashMap 的扩容机制是为了在数据量增加时,自动调整哈希表的容量,以保持性能。这个机制确保了 HashMap 在处理大量数据时能够高效地存储和检索键值对。

你可能感兴趣的:(java,数据结构,哈希算法,算法)