记录哈希表的底层原理探索

简介: HashMap是基于哈希表的键值对存储结构,支持唯一键、允许多个null值。通过哈希函数将键映射到数组索引,采用拉链法解决冲突,Java 8后引入红黑树优化长链表性能。当负载因子达0.75或链表长度≥8且数组长度≥64时触发扩容或树化,提升查询效率。

关于 HashMap

HashMap 是什么?

HashMap 是基于哈希表的数据结构,用于存储键值对(key-value)

特点:键唯一,值可以重复,允许一个 null ,多个 null

核心点:将键的哈希值映射到数组索引位置,利用数组+链表(Java1.8 之后为数组+链表+红黑树)来处理哈希冲突

哈希冲突是什么?怎么解决?

哈希冲突:当两个不同的数经过哈希函数计算后得到了同一个结果,即他们会被映射到哈希表的同一个位置时,即称为发生了哈希冲突。

常用的解决方法

拉链法

使用链表或者其他数据结构来存储哈希冲突的键值对,将它们链接在同一个哈希桶中。

把所有同义词存储在一个链表中

假设现在有一个哈希函数为H(key)=key%13

当发生哈希冲突的时候,会将新的键值对添加到链表中,当需要查找该值的时候,会先通过哈希函数找到桶,然后遍历链表找到该值

img

开放定址法

在哈希表中寻找另一个位置(哈希桶)存放哈希键值对,而不是存放在链表中

常见的策略有:线性探测、平方探测、双重三列、伪随机序列

公式:
$$ H_i=(H(key)+d_i) \% m $$
参数介绍:

  • H_i:发生第 i 次冲突的散列地址
  • H(key):初始散列地址
  • d_i:偏移量
  • m:散列表的长度

线性探测

  • 逐一检查下一个哈希桶(H(key)++),直到找到一个空桶为止
  • 在线性探测d_i相当于一个等差数列,d_i= 0,1,2,3,4….,m-1

平方探测

利用平方探测公式逐渐增加偏移量检查下一个哈希桶,直到找到一个空桶为止,公式为:
$$ d_i=i^2,-(i^2) $$
例如
$$ d_i= 0^2, 1^2, -1^2, 2^2, -2^2,….,k^2, -k^2; k <= m/2 $$

双散列表

公式:
$$ H_i=(hash1(key) + i*hash2(key)) \% m $$

$$ hash1(key)=key\% m $$

$$ hash2(Key)=PRIME - (key\%PRIME) $$

  • 当第一个哈希函数发生冲突的时候,就会使用第二个哈希函数来寻找空的哈希桶,如此反复,直到找到空的哈希桶

  • 偏移量
    $$ d_i=i*hash2(key) $$

哈希扩容

HashMap中的扩容是基于负载因子(load factor)决定的,散列表的平均查找长度依赖于负载因子a,而不是n或者m

$$ 负载因子 a = \frac{表中记录数n}{散列长度m} $$
负载因子a默认是0.75,也就是当表中记录n(已存储元素数量)超过散列长度的 75%,散列表就会发生扩容

当发生扩容的时候,HashMap的容量会扩大为当前的 2 倍。扩容时,HashMap需要将所有元素重新分配到新的哈希桶,这个过程为rehashing

HashMap 的红黑树优化

首先看hashmap中的一个常量值:

TREEIFY_THRESHOLD

使用树而不是列表来表示一个桶的桶计数阈值。当向一个至少包含此数量节点的桶中添加元素时,这些桶会被转换为树。该值必须大于2,且至少应为8,以便与树删除操作中的假设相一致,即收缩后应重新转换为普通桶。

UNTREEIFY_THRESHOLD

在调整大小操作期间将(拆分)桶标记为非树状化的桶计数阈值。该值应小于TREEIFY_THRESHOLD,且最多为6,以便与移除操作下的收缩检测相协调。

MIN_TREEIFY_CAPACITY

可以实施树化操作的最低表容量。否则,如果桶中节点过多,则会对表进行重新调整大小。应至少设置为4 * TREEIFY_THRESHOLD,以避免在重新调整大小和树化阈值之间产生冲突。

源码:

static final int TREEIFY_THRESHOLD = 8;

static final int UNTREEIFY_THRESHOLD = 6;

static final int MIN_TREEIFY_CAPACITY = 64;

转换为红黑树的时机

HashMap的链表长度 >= 8 且数组的长度>=64的时候会树化,即链表转换成红黑树

在源码的putVal(...)函数中的树化判定条件

TREEIFY_THRESHOLD的默认阈值,因为负载因子是0.75,而 8 * 0.75 = 6,也就是当表中记录数超过6并且散列表的长度为 8 的时候就会发生树化

img

final void treeifyBin(Node<K,V>[] tab, int hash) {
   
    int n, index; Node<K,V> e;
    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
        resize();
    else if ((e = tab[index = (n - 1) & hash]) != null) {
   
        TreeNode<K,V> hd = null, tl = null;
        do {
   
            TreeNode<K,V> p = replacementTreeNode(e, null);
            if (tl == null)
                hd = p;
            else {
   
                p.prev = tl;
                tl.next = p;
            }
            tl = p;
        } while ((e = e.next) != null);
        if ((tab[index] = hd) != null)
            hd.treeify(tab);
    }
}

转换为链表的时机

当哈希表的长度为 6 的时候,就会退化为链表

在源码中的split(...)函数中的红黑树退化为链表的判定条件

untreeify()为转链表化函数

img

end…

参考文章:

说说Java中HashMap的原理?

一篇博客让你认识哈希冲突和解决方法

相关文章
|
24天前
|
监控 关系型数据库 MySQL
《理解MySQL数据库》从单机到分布式架构演进
MySQL是全球最流行的开源关系型数据库,以其稳定性、高性能和易用性著称。本文系统解析其发展历程、核心架构、存储引擎、索引机制及在Java生态中的关键作用,涵盖性能优化、高可用设计与云原生趋势,助力开发者构建企业级应用。
|
24天前
|
运维 开发者 Docker
一、Docker:一场颠覆应用部署与运维的容器革命
Docker的出现,就是为了解决“在我电脑上能跑”这个老大难问题。它像个魔法集装箱,把你的程序和它需要的所有东西(比如库、配置)都打包好,这样无论在哪运行,环境都一模一样。理解它很简单,就三个核心玩意儿:镜像是程序的“安装包”,容器是跑起来的程序,而仓库就是存放和分享这些“安装包”的地方。
308 6
|
1月前
|
人工智能 Java Nacos
基于 Spring AI Alibaba + Nacos 的分布式 Multi-Agent 构建指南
本文将针对 Spring AI Alibaba + Nacos 的分布式多智能体构建方案展开介绍,同时结合 Demo 说明快速开发方法与实际效果。
1419 52
|
23天前
|
缓存 Windows
彻底卸载软件且不留痕!卸载+清理+启动项优化,彻底清理残留信息
一款小巧高效的卸载工具,仅3.85M,主打彻底清理软件残留文件、注册表、服务等。支持强制卸载、应用商店程序移除、浏览器扩展管理、注册表清理、垃圾文件扫描及空文件夹清理,并提供文件粉碎、快捷方式修复等功能,界面简洁且可换肤,是系统清理的得力助手。
171 6
|
18天前
|
Ubuntu Linux 开发工具
Linux操作技巧: 修改网卡名称方法详述
以上就是在Linux系统中修改网卡名称的详细步骤。希望这些信息能帮助到有此需求的用户。
127 12
|
24天前
|
人工智能 自然语言处理 前端开发
构建AI智能体:六、体验Trae指定Qwen-Turbo模型自动生成问答系统
本文介绍如何使用字节跳动的AI编程工具Trae与阿里通义千问Qwen-Turbo模型,快速生成一个智能问答系统。通过图文结合方式,演示从环境搭建、指令生成到界面优化的全过程,涵盖前后端代码自动生成、模型调用封装及交互优化技巧,展现AI辅助开发的高效与趣味,助力开发者提升生产力。
432 12
|
24天前
|
JSON 自然语言处理 安全
《服务治理》RPC框架序列化协议深度解析
序列化是将对象转换为字节流的过程,反序列化则是将字节流恢复为对象的过程。在RPC调用中,序列化协议的性能直接影响整个系统的吞吐量和延迟。
|
1月前
|
人工智能 运维 Cloud Native
2025 云栖精选资料:《从云原生到 AI 原生核心技术与最佳实践》PPT 免费下载
一本合集,四大主题,覆盖 AI 原生技术的核心版图。立即获取,与行业领跑者同行,抢占 AI 原生时代的技术先机!
|
28天前
|
人工智能
一个帮运营写产品详情页的AI指令
分享一套实用的电商详情页AI生成指令模板,涵盖标题、卖点、场景、参数、保障等核心模块,帮助运营、产品经理等快速产出80分初稿,大幅提升效率。适配主流AI工具,结合人工优化,轻松应对多平台需求。
724 7