问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

HashMap解密:揭秘高效存储与快速检索的魔法

创作时间:
作者:
@小白创作中心

HashMap解密:揭秘高效存储与快速检索的魔法

引用
1
来源
1.
https://m.w3cschool.cn/article/6725182.html

HashMap是Java中使用最广泛的数据结构之一,它通过高效的键值对存储和检索机制,在各种应用场景中发挥着重要作用。本文将深入探讨HashMap的底层原理,包括其数据结构、哈希算法、碰撞解决方法以及具体的工作流程,帮助读者全面理解这一核心数据结构。

数据结构

HashMap的底层数据结构由数组和链表(或红黑树)组成。数组用于存储元素的桶(bucket),每个桶是一个链表或红黑树的头节点。当某个桶内的元素数量过多时,链表会自动转换为红黑树,以优化检索效率。

哈希算法

HashMap通过哈希算法将键映射到数组的索引位置。核心在于hashCode()方法,该方法根据键的特性生成一个整数哈希码,代表键在数组中的存储位置。

碰撞解决方法

在哈希算法中,不同键可能产生相同的哈希码,这种现象称为碰撞。HashMap采用链表和红黑树来处理碰撞问题:

  1. 当元素插入HashMap时,首先根据键的哈希码计算数组索引。
  2. 如果索引位置为空,则直接插入元素。
  3. 如果索引位置已有元素,则遍历链表或红黑树,检查键是否已存在:
  • 如果键已存在,则更新对应的值。
  • 如果键不存在,则将新元素添加到链表或红黑树的末尾或合适位置。

当链表长度超过8个节点且数组长度大于64时,链表会转换为红黑树,以提升检索效率。

源码分析

以下是处理链表碰撞的核心代码:

// 遍历链表
for (int binCount = 0; ; ++binCount) {
    // 遍历到链表最后一个节点
    if ((e = p.next) == null) {
        p.next = newNode(hash, key, value, null);
        // 如果链表元素个数大于等于TREEIFY_THRESHOLD(8)
        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
            // 红黑树转换(并不会直接转换成红黑树)
            treeifyBin(tab, hash);
        break;
    }
    if (e.hash == hash &&
        ((k = e.key) == key || (key != null && key.equals(k))))
        break;
    p = e;
}

工作原理

HashMap在执行插入、获取或删除操作时,遵循以下步骤:

  1. 根据键的hashCode()方法计算哈希码。
  2. 根据哈希码找到数组索引位置。
  3. 如果索引位置为空,直接插入元素。
  4. 如果索引位置已有元素,检查键是否已存在:
  • 如果键已存在,则更新值。
  • 如果键不存在,则将元素插入链表或红黑树。
  1. 如果链表长度过长且数组长度足够大,将链表转换为红黑树。
  2. 根据需要调整数组大小(扩容或收缩),以保持较低的负载因子。

总结

HashMap是一种高效的键值对存储和检索数据结构。其底层原理基于数组、链表和红黑树,通过哈希算法将键映射到数组索引位置。碰撞问题通过链表和红黑树的使用得以解决。理解HashMap的底层原理对于优化性能和避免潜在问题至关重要。通过合理选择哈希函数和调整负载因子,可以确保HashMap在各种场景下都能提供高效的数据存储和检索能力。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号