HashMap原理(一):哈希函数的设计

news2024/11/17 17:29:49

哈希函数的作用与本质

HashMap用来存储存在映射关系的数据对{key, value},在内部通过构造复合数据结构来封装数据对,即

//伪代码,非源码
class Pair<K, V> {
     public K key;
     public V value;
}

假设用来存储数据对的哈希数表为table,数据对Pair的存储位置通过计算key得到,key => index,则Pair将存储在table[index]处。
哈希函数就是用来计算哈希索引的工具。
fun(key,table) = index, 0 <= index < table.length
入参key为整数,若key不为整数,则需要先将key转化为整数再参与计算。在Java中,每个对象都有一个public int hashCode();方法,起的就是这个转化作用。

哈希函数设计

构造哈希函数最常见的策略是取余法,即index = int_key % table.length
HashMap也是采用取余法构造哈希函数,并强制table.length为2的整数次幂,即 2 n {2}^{n} 2n,这样便可采用位运算计算余数以提高运算效率:(table.length - 1) & key.hashCode()
因为当table.length = 2^n时,其二进制形式只有第n位为1,其余皆为0。任何一个整数对table.length求余,实际上就是取这个整数的低n位的值。
例如table.length = 16 = 2^4,其二进制形式为:
0000 0000 0000 0000 0000 1000
那么18 % 16,
在这里插入图片描述

而(table.length -1)的二进制形式,除了低(n - 1)位为1,其余皆为0。恰好是对任意一个整数低(n - 1)位的遮罩, 当用这个遮罩与任意一个整数进行位或操作时,恰好得到这个整数对table.length求余的余数。
以table.length = 16 = 2 ^ 4为例,table.length -1 = 15,即
0000 0000 0000 0000 0000 0000 0000 0111
那么18 & (16 -1) = 18 % 16 = 2,
在这里插入图片描述

哈希表初始容量的校正

创建HashMap时,允许指定哈希表的初始容量,即table.length。HashMap没有强制要求使用者传入的初始容量为2的整数次幂,而是在内部自动转化。若使用者传入的初始容量为c,那么转化后的哈希表容量为大于等于c的最小的一个2的整数次幂。如,9~15都会转为为16 = 2^4,
17~31都会转成2^5 = 32,以此类推。
从二进制的角度看,使用者传入的初始容量为c(先不考虑c恰好是2的整数次幂的情况),如果它比特值为1的最高位是第k位,那么转化后的值就是2^(k+1)。以129 = 2 ^7 + 1为例,比特值
为1的最高位是7,那么转化后的值便是2^8 = 256。
在这里插入图片描述
HashMap采用的策略是,如果c的比特值为1的最高位是第k位,即c=2^(k-1),那么将低k位全部置为1,再把结果值 + 1,恰好得到转换后的目标容量。以129 = 2 ^7 + 1为例,比特值为1的最高位是第8位,那么将低7位全部置为1得到255,255再加1等于256。
在这里插入图片描述

具体计算方法上,将c不断进行无符号右移再与原值进行位或操作,我们还是通过c = 129,k = 8来一步步说明。
第一步,将129无符号右移一位,得到结果64,结果的第k-1位必定为1。
在这里插入图片描述
然后将129与64做位或操作得到结果193,由于位或操作中,两个比特为只要有一个为1,那么结果必为1,如此,确保了最终结果第k-1位变为1。
在这里插入图片描述
第二步,经过第一步,第k位,k-1位都为1,所以我们可以把193无符号右移2位,得到结果48,结果的第k-2位及第k-3位必定为1。
在这里插入图片描述
然后将193与48做位或操作,得到结果241,最终结果第k位到第(k - 3)位,总共四位都变为1。
在这里插入图片描述
第三步,经过前面的操作,得到的结果241的第k位到(k-3)位,总共四位均变为1,所以将241无符号右移4位,得到结果15,其低4位均为1。
在这里插入图片描述
再将241与48进行位或操作,得到结果255,至此目标结果的低8位全部置为1。
在这里插入图片描述
因为用户传入的初始容量c,其比特值为1的最高位可能是第31位,所以为了囊括所有的可能,会继续无符号右移,直至移够31位,每次移动的位数恰好是上一次的2倍。
对于上面的例子,接下来要无符号右移8位。将255 无符号右移8位得到0。
在这里插入图片描述
将255与0进行位或,结果不变还是255。
在这里插入图片描述
接下来,位移16位,结果为0,再与255位或,结果还是255。至此已经总共无符号右移了(1 + 2 + 4 + 8 + 16) = 31位,位移结束。
最后,255 + 1 = 256。
在这里插入图片描述

按照上面的算法,哈希表初始容量的校正代码如下:

int tableSizeFor(int cap) {
    int n = cap;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return n
    }

我们还有遗留的一个问题没有讨论,假如使用者传入的初始容量c本来就是2的整数次幂,如c = 128 = 2^(k - 1),k = 8,那么将低(k - 1) = 7位全部置为1,将得到255。
在这里插入图片描述
那么,如果想把这样的c也统一到我们的计算公式里,我们只需要在开始位移前,将初始容量减1,然后再开始位移。比如c = 128,c - 1 = 127,127的二进制表示法中,比特值为1的最高位是第7位,将其低6位全部置为1,结果还是127,然后加1得到目标结果128。
在这里插入图片描述
对于初始容量c不是2的整数次幂的情况,将c - 1再通过tableSizeFor计算,结果跟直接通过c计算的结果一致。
最后再考虑下边界值问题。
当c = 0,直接取1 = 2^0,
在java中,一个int值能表示的最大的2的整数次幂是2^(k -1),k = 31,即2^30,所以当c的二进制形式中,比特值为1最
高位为31时,那么位移结束后目标结果将是(2^32) -1,
即除了符号位全是1,此时再加1将产生溢出,所以直接取2^30。
最终的adjustCapacity如下:

int tableSizeFor(int cap) {
   int n = cap - 1;
   n |= n >>> 1;
   n |= n >>> 2;
   n |= n >>> 4;
   n |= n >>> 8;
   n |= n >>> 16;
   return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

哈希表容量为2的整数次幂的缺陷及解决办法

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TCP状态转换

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 TCP状态转换专栏&#xff1a;《Linux从小白到大神》《网络编程》 TCP状态转换示意图如下 针对上面的示…

项目结束先别着急庆祝,项目经理还有这些事要做

项目管理生命周期结束阶段的目的是确认项目可交付成果的完成&#xff0c;使项目发起人满意&#xff0c;并向所有参与者和利益相关者传达项目的最终处置和状态。 项目结束确保项目的所有参与者和利益相关者都清楚后续活动&#xff08;如新项目、服务过渡、SLA等&#xff09;&a…

【ChatGPT情商大考验】ChatGPT教我谈恋爱

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

graph在细粒度分类中的应用

目录基于Graph-Propagation的相关性学习AAAI2020基于graph的高阶关系发现CVPR2021基于Graph-Propagation的相关性学习AAAI2020 来源&#xff1a;Graph-Propagation Based Correlation Learning for Weakly Supervised Fine-Grained Image Classification&#xff08;这或许是第…

MATLAB R2022b 安装教程

MATLAB R2022b 安装教程MathWorks 于2022年9月发布了 MATLAB 和 Simulink 产品系列的最新版本 Matlab R2022b版本 &#xff0c;加入两个新产品&#xff1a; Medical Imaging Toolbox — 可视化、配准、分割和标注二维及三维医学图像Simscape Battery — 设计和仿真电池和储能系…

HiveSql一天一个小技巧:如何巧用分布函数percent_rank()求去掉最大最小值的平均薪水问题

0 问题描述参考链接(3条消息) HiveSql面试题12--如何分析去掉最大最小值的平均薪水&#xff08;字节跳动&#xff09;_莫叫石榴姐的博客-CSDN博客文中已经给出了三种解法&#xff0c;这里我们借助于此题&#xff0c;来研究如何用percent_rank()函数求解&#xff0c;简化解题思路…

Kafka(五)生产者向发送消息的执行流程

&#xff08;1&#xff09;生产者要往 Kafka 发送消息时&#xff0c;需要创建 ProducerRecoder,代码如下&#xff1a; ProducerRecord<String,String> record new ProducerRecoder<>("CostomerCountry","Precision Products","France&q…

新闻稿的制作流程:从确定新闻稿目的到将其分发给媒体

对于任何希望向媒体和公众传达具有新闻价值的信息的组织来说&#xff0c;新闻稿都是必不可少的工具。精心制作的新闻稿可以帮助您宣传您的业务、产品或服务&#xff0c;并可以产生有价值的媒体报道。在本文中&#xff0c;我们将指导您完成新闻稿的制作过程&#xff0c;从确定新…

08_MySQL聚合函数

1. 聚合函数介绍什么是聚合函数聚合函数作用于一组数据&#xff0c;并对一组数据返回一个值。聚合函数类型AVG()SUM()MAX()MIN()COUNT()注意&#xff1a;聚合函数不能嵌套调用。比如不能出现类似“AVG(SUM(字段名称))”形式的调用。1.1 AVG和SUM函数可以对数值型数据使用AVG 和…

上海亚商投顾:ChatGPT概念领跌 两市约3800股下跌

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪三大指数今日继续调整&#xff0c;创业板指午后一度跌超1%。ChatGPT、AIGC概念股集体走低&#xff0c;三六零跌超8%&…

面试阿里测开岗,被面试官针对,当场翻脸,把我的简历还给我,疑似被拉黑...

好家伙&#xff0c;金三银四一到&#xff0c;这奇葩事可真是多&#xff0c;前两天和粉丝聊天&#xff0c;他说前段时间面试阿里的测开岗&#xff0c;最后和面试官干起来了。 我问他为什么&#xff0c;他说没啥&#xff0c;就觉得面试官太装了&#xff0c;就爱问一些虚而不实的…

2023CS双非保研985经验分享(南大、华科、中科大科学岛、国防科大、西交、中南、深圳大学、北邮、中科院等)

前言&#xff1a; 2022保研以来&#xff0c;因为自己的双非背景&#xff0c;要与985、211的排名靠前的计科大佬竞争&#xff0c;不自信、焦虑无时无刻的包围着我&#xff1b;所幸&#xff0c;一路以受到了许多学长、学姐耐心的帮助&#xff0c;也有很多保研的同学一路互相支撑。…

antd4里table的滚动是如何实现的?

rc-table里Header、Footer、TableBody实现保持同频滚动的方法 场景&#xff1a;Header、Footer都有&#xff0c;Table设置了scrollX&#xff0c;才关注同频滚动 那么是如何实现的&#xff1f; 监听onScroll方法获取到滚动条向左的滚动的距离scrollLeft&#xff1b;同时给三个…

九种分布式ID解决方案

文章目录背景1、UUID2、数据库自增ID2.1、主键表2.2、ID自增步长设置3、号段模式4、Redis INCR5、雪花算法6、美团(Leaf)7、百度(Uidgenerator)8、滴滴(TinyID)总结比较背景 在复杂的分布式系统中&#xff0c;往往需要对大量的数据进行唯一标识&#xff0c;比如在对一个订单表…

浏览器事件循环

事件循环 一、浏览器的进程模型 1.何为进程&#xff1f; 程序运行需要有它自己专属的内存空间&#xff0c;可以把这块内存空间简单的理解为进程 每个应用至少有一个进程&#xff0c;进程之间相互独立&#xff0c;即使要通信&#xff0c;也需要双方同意。 2.何为线程&…

多部委联合举办中国人工智能大赛启动会在厦召开,快商通亮相发言

站在“第二个百年奋斗目标”的新起点上&#xff0c;为深入推动我国人工智能产业创新发展&#xff0c;发掘一批人工智能优秀团队&#xff0c; 国家互联网信息办公室、工业和信息化部、公安部、国家广播电视总局、厦门市人民政府将联合主办第四届中国人工智能大赛 。快商通联合创…

渗透之认识Metasploit

Metasploit: The Metasploit Framework 的简称。是一款开源的安全漏洞检测工具&#xff0c;可以帮助安全和IT专业人士识别安全性问题&#xff0c;验证漏洞的缓解措施&#xff0c;并管理专家驱动的安全性进行评估&#xff0c;提供真正的安全风险情报。 MSF 高度模块化&#xff…

Normalization

1、BN&#xff08;Batch Normalization&#xff09; 深度网络参数训练时内部存在协方差偏移&#xff08;Internal Covariate Shift&#xff09;现 象&#xff1a;深度网络内部数据分布在训练过程中发生变化的现象。训练深度网络时&#xff0c;神经网络隐层参数更新会导致网络输…

(十九)操作系统-进程互斥的硬件实现

文章目录一、知识总览二、中断屏蔽方法三、TestAndSet指令四、Swap指令五、总结一、知识总览 二、中断屏蔽方法 利用“开/关中断指令”实现&#xff08;与原语的实现思想相同&#xff0c;即在某进程开始访问临界区到结束访问为止都不允许被中断&#xff0c;也就不能发生进程切换…

安装_配置参数解读_集群安装配置_启动选举_搭建启停脚本---大数据之ZooKeeper工作笔记004

这里首先下载zookeeper安装包,可以看到官网地址 找到download 点击下载 找到老一点的,我们找3.5.7 in the archive 点击 然后这里找到3.5.7这一个 然后下载这个-bin.tar.gz这个