HashMap扩容为什么每次都是之前的2倍

一. 背景介绍

HashMap的底层是通过数组+链表+红黑树的数据结构来存放数据的。我们知道,当新添加元素的key值出现了hash碰撞,就会在同一个bucket中形成链表或者红黑树。当键值对的数量超过阈值时就会扩容,将以前处于同一个链表或者红黑树上的元素打散,在新数组的 bucket 上进行重新分布。

当HashMap在初始化没有指定容量的情况下,首次添加元素时,数组的容量为16;当超出阈值,数组容量为扩容为之前的2倍。

那么问题来了,为什么HashMap会将首次初始化容量设置为16,而后续每次扩容都是之前的2倍?而不是像ArrayList首次为10,后续为1.5倍呢?这可是我们在面试时的一个高频考点哦!

二. 问题解答

2.1 对应源码分析

其实要想回答出上面提出的问题,我们可以从HashMap的源码里找到答案,如下图所示:

其中 n 为数组的长度,n - 1 为数组的最大索引值。(n - 1)& hash 的意思是将每个元素key的hash值,与最大索引值进行相与操作。然后判断对应的 bucket 位置是否有元素,如果没有元素则在对应的 bucket 位置直接添加;如果有元素,则形成链表或者红黑树

2.2 深入分析

各位看官,你现在可能对上面的内容还是有点云里雾里,别急,让我们再来看一组数据:

长度最大索引二进制数

当数组初始长度为16的时候,每次扩容都为之前的2倍,那么就保证了每次扩容之后新数组的最大索引值对应的二进制数为全1。根据2.1小节中,图片标识的(n-1)&hash,那么就能保证添加到HashMap中key的hash值与最大索引相与时,能够最大化的分散到HashMap所有的 bucket 中,进而最大化避免出现 hash碰撞而形成链表或者红黑树。

我们再反向地跟各位看官论证一下。假如说 HashMap的初始化长度是10,那么最大索引值为9,而9对应的二进制数是 1001。那么key的hash值与 9相与,结果只可能为 0、1、8、9,那么新增的数据永远只能放到数组索引为 0、1、8、9这四个位置,这就大大增加了出现链表和红黑树转换的概率。

所以初始化为16,每次扩容是之前的2倍,这就大大降低了链表和红黑树转换的概率,自然也就提高了HashMap的性能。


举例说明:

向集合中添加元素时,会使用(n - 1) & hash的计算方法来得出该元素在集合中的位置,其中n是集合的容量,hash是添加的元素进过hash函数计算出来的hash值。

HashMap的容量为什么是2的n次幂,和这个(n - 1) & hash的计算方法有着千丝万缕的关系,符号&是按位与的计算,这是位运算,计算机能直接运算,特别高效,按位与&的计算方法是,只有当对应位置的数据都为1时,运算结果也为1,当HashMap的容量是2的n次幂时,(n-1)的2进制也就是1111111***111这样形式的,这样与添加元素的hash值进行位运算时,能够充分的散列,使得添加的元素均匀分布在HashMap的每个位置上,减少hash碰撞,下面举例进行说明。

当HashMap的容量是16时,它的二进制是10000,(n-1)的二进制是01111,与hash值得计算结果如下

上面四种情况我们可以看出,不同的hash值,和(n-1)进行位运算后,能够得出不同的值,使得添加的元素能够均匀分布在集合中不同的位置上,避免hash碰撞。

下面就来看一下HashMap的容量不是2的n次幂的情况,当容量为10时,二进制为01010,(n-1)的二进制是01001,向里面添加同样的元素,结果为:

可以看出,有三个不同的元素与不同的hashCode经过&运算得出了同样的结果(index),严重的hash碰撞了。

终上所述,HashMap计算添加元素的位置时,使用的位运算,这是特别高效的运算;另外,HashMap的初始容量是2的n次幂,扩容也是2倍的形式进行扩容,是因为容量是2的n次幂,可以使得添加的元素均匀分布在HashMap中的数组上,减少hash碰撞,避免形成链表的结构,使得查询效率降低!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/1106.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pytorch实现深度神经网络与训练

目录 1. 随机梯度下降算法 2.优化器 3. 损失函数 3.1 均方误差损失 3.2 交叉熵损失 4.防止过拟合 4.1 过拟合的概念 4.2 防止过拟合的方法 5. 网络参数初始化 5.1 网络参数初始化方法 5.2 参数初始化方法应用实例 1.针对某一层的权重进行初始化 2.针对一个网络的权…

学习 Python 之 Pygame 开发魂斗罗(一)

学习 Python 之 Pygame 开发魂斗罗(一)Pygame回忆Pygame1. 使用pygame创建窗口2. 设置窗口背景颜色3. 获取窗口中的事件4. 在窗口中展示图片(1). pygame中的直角坐标系(2). 展示图片(3). 给部分区域设置颜色5. 在窗口中显示文字6. 播放音乐7. 图片翻转与…

全网超详细的vue双向数据绑定的原理

文章目录1. 文章引言2. vue如何实现数据的双向绑定3. 什么是Object.defineProperty4. 什么是setter和getter1. 文章引言 假设,我在文本框中输入文字,在p标签中动态展示我输入的文字,如下图所示: 实现上述效果的代码如下所示&#…

通过百度文心一言大模型作画尝鲜,感受国产ChatGPT的“狂飙”

3月16日下午,百度于北京总部召开新闻发布会,主题围绕新一代大语言模型、生成式AI产品文心一言。百度创始人、董事长兼首席执行官李彦宏,百度首席技术官王海峰出席,并展示了文心一言在文学创作、商业文案创作、数理推算、中文理解、…

【数据结构】万字深入浅出讲解单链表(附原码 | 超详解)

🚀write in front🚀 📝个人主页:认真写博客的夏目浅石. 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝 📣系列专栏:C语言实现数据结构 💬总结:希望你看完…

LeetCode刷题——贪心法(C/C++)

这里写目录标题[中等]买卖股票的最佳时机 II[中等]移掉k位数字[中等]跳跃游戏[中等]跳跃游戏 II[中等]加油站[中等]划分字母区间[中等]无重叠区间[中等]用最少数量的箭引爆气球[中等]买卖股票的最佳时机 II 原题链接题解 最简单的思路,效率不高,只要明天…

【Linux】Linux项目自动化构建工具make makefile

文章目录1. 背景2.实例3.原理4.项目清理5. 文件属性中的三个时间6. Linux下第一个小程序——进度条6.1 前置知识1:缓冲区6.2前置知识2:回车换行6.3进度条的实现7 Linux下git的”三板斧“1. 背景 一个工程中的源文件不计其数,其按类型、功能、…

【码字必看】一篇文章带你轻松上手MarkDown

文章目录🍬前言😮什么是MarkDown🧐为什么要学习MarkDown🔑使用MarkDown的工具📚MarkDown基础语法🥝标题🥥字体(斜体、粗体、粗斜体)🍇各种线(分割…

华为nat配置实验:内网能够访问外网,内网服务器80端口映射出去

一 需求分析1.1 需求公司A在北京,公司B在上海,本次实验仅仅模拟局域网内出口路由器的配置,公司A业务流量较大,并且预算有限。公司B模拟外网的一个小型局域网,要求公司B的主机能够访问公司A的web服务器。1.2 分析采用na…

Django 4.0文档学习(一)

本系列文章基于Django4.0版本官方网站文档学习 使用开发工具为pycharm > python -m django --version 4.0文章目录编写你的第一个 Django 应用,第 1 部分创建项目用于开发的简易服务器创建应用编写第一个视图编写你的第一个 Django 应用,第 2 部分数…

移动端适配

​ 是看的b站一个老哥的视频,做的汇总,讲的嘎嘎棒。视频链接:b站链接 视口viewport pc端视口就是可视化的窗口,不包含浏览器工具栏但是移动端,不太一样,布局的视口和可见的视口是不太一样的 移动端的网页…

openstack

云计算架构 openstack整体架构 openstack身份服务-Keystone 管理层次结构 Keystone三大组件 服务(Server) 身份(Identity)服务 资源(Resource)服务 分配(Assignment)服务 令牌&am…

Kaggle实战入门:泰坦尼克号生生还预测

Kaggle实战入门:泰坦尼克号生生还预测1. 加载数据2. 特征工程3. 模型训练4. 模型部署泰坦尼克号(Titanic),又称铁达尼号,是当时世界上体积最庞大、内部设施最豪华的客运轮船,有“永不沉没”的美誉&#xff…

小黑子—多媒体技术与运用基础知识:一

多媒体技术与运用1.0多媒体系列第一章1. 计算机媒体概述1.1 媒体的分类1.2 小结2. 多媒体概述2.1 与多媒体技术的概念3. 多媒体技术特点3.1 多样性3.2 交互性3.3 实时性3.4 集成性4. 多媒体关键技术4.1 多媒体关键解码技术4.2 多媒体实时处理技术4.3 多媒体软硬件系统4.4 多媒体…

VSCode 开发配置,一文搞定(持续更新中...)

一、快速生成页面骨架 文件 > 首选项 > 配置用户代码片段 选择需要的代码片段或者创建一个新的,这里以 vue.json 举例: 下面为我配置的代码片段,仅供参考: 1. Vue2 JS 在 .vue 文件中输入 vue2 回车。即可快速生成页…

SparkSQL-SparkOneHive

部署 连接Hive操作 小试牛刀:Hive版本的WordCount 从MySQL中读取数据存储到hive中 部署 1、Spark 要接管 Hive 需要把 hive-site.xml 拷贝到 conf/目录下 2、把 Mysql 的驱动 copy 到 jars/目录下 3、 如果访问不到 hdfs,则需要把 core-site.xml 和…

使用busybox构建根文件系统

目录 1 下载busybox 2 修改Makefile 3 配置busybox 4 编译安装 4.1 /usr/include/unistd.h:203: error: conflicting types for gid_t 4.2 miscutils/seedrng.c:45:24: fatal error: sys/random.h: No such file or directory 4.3 Makefile:405: *** mixed implicit and…

Android开发 Layout布局 ScrollView

1.LinearLayout 属性 orientation:内部组件排列方式,可选vertical、horizontal,默认horizontal layout_weight: 与平级组件长宽比例,需要将layout_width、layout_height其中一个设置为0dp,表明长或宽与平级组件的长…

Nuxt.js项目开发过程遇到的问题以及对Nuxt.js的学习与总结

文章目录📋前言💻Nuxtjs3快速了解🎯nuxtjs是什么?官网是这样介绍它的。🎯关于nuxtjs的SSR开发🧩SSR应用场景🧩nuxtjs的特性💻nuxtjs的初始目录结构🎯关于各个目录的解释&…

WEB前端第三次作业——CSS样式案例

WEB前端第三次作业——CSS样式案例 做出如下图中的效果 用到的图片素材均来源于对应网站源代码 1&#xff0c; <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>.goods{width: 220px;height: …
最新文章