【数据结构】29、hashmap=》tableSizeFor 中求大于等于当前数的最小2的幂
最近面试被问到hashmap的实现,因为前段时间刚好看过源码,显得有点信心满满,但是一顿操作下来的结论是基础不够扎实。。。
好吧,因为我开始看hashmap是想了解这到底是一个什么样的机制,具体有啥作用,并没有过于细节去了解,所以问到细节的地方就难免漏洞百出,
回来之后,决定吧容器类的实现原理,去专研一下,目的是为了以后写代码自己可以去优化它
好了,不BB了,直接上代码,hashmap中有这么一段代码
//容器最大容量
static final int MAXIMUM_CAPACITY = 1 << 30; /**
*
* @program: y2019.collection.MyHashMap
* @description: 这个方法用于找到大于等于initialCapacity的最小的2的幂(initialCapacity如果就是2的幂,则返回的还是这个数)。
* @auther: xiaof
* 总结:
* 1.说白了就是为了保证所有的位数(二进制)都是1,那么就可以保证这个数就是2的幂
* 2.不断做无符号右移,是为了吧高位的数据拉下来做或操作,来保证对应的底位都是1
* @date: 2019/6/25 10:25
*/
public static final int tableSizeFor(int cap) {
//这是为了防止,cap已经是2的幂。如果cap已经是2的幂
int n = cap - 1;
//第一次右移,由于n不等于0(如果为0,不管几次右移都是0,那么最后有个n+1的操作),则n的二进制表示中总会有一bit为1
//这里无符号右移一位之后做或操作,那么会导致原来有1的地方紧接着也是1
//比如00000011xxxxxxxx
//还有一点无符号右移是为了避免前位补1,导致数据溢出,因为负数是以补码的形式存在的,那么就会再高位补1
n |= n >>> 1;
//第二次无符号右移,并做或操作
//00000011xxxxxxxx=>0000001111xxxxxx 这个时候就是4个1
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
//由于int最大也就是2的16次幂,所以到16停止
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
我开始的不明白的地方是为什么要做4次右移???为什么要做无符号右移???
那么我手动时间一个low点的版本我们对比一下
public static final int tableSizeFor2(int cap) {
        //这是为了防止,cap已经是2的幂。如果cap已经是2的幂
        int n = cap - 1;
        n |= n & 0xffff;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
原谅我的无知,我的第一反应就是这个,想都没想为什么不这样做。。。
结果发现相差甚远

第三行就是我这第二个方法得到的值,除了吧负数排除之外,没啥屌用,就是把原来的n去掉符号之后做了一次与运算
这个题的原理是获取到这个入参的位数,然后获取2的N次幂
public static final int tableSizeFor3(int cap) {
        //这是为了防止,cap已经是2的幂。如果cap已经是2的幂
        int n = (cap - 1) & 0xffff;
        String hex = Integer.toBinaryString(n);
        return (cap <= 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : (int) Math.pow(2, hex.length());
    }
我们再这样处理

我们发现好像很接近了,我们发现n为1的时候,我们得到的长度是2,如果是以大于等于这个数的2的N次幂的话,我觉得我下面这个方法视乎更符合要求

接下来我们来试试性能?
当我们需要计算的数量达到1000000的时候,我们发现,这两个操作的性能相差有点大。。。

好吧,结论发现就是,jdk的源码不亏是经过千锤百炼的,一些看不懂的操作也许就是故意而为!!!
多关注这些看不懂的操作,学会了你也是大神!!!
参考文章:
https://blog.csdn.net/fan2012huan/article/details/51097331
【数据结构】29、hashmap=》tableSizeFor 中求大于等于当前数的最小2的幂的更多相关文章
- 分页过滤SQL求总条数SQL正则
		
public static void main(String[] args) throws Exception { String queryForScanUsers_SQL = "selec ...
 - hashMap tableSizeFor 实现原理
		
基于jdk1.8 hashMap实现,要求容量大小是2的整次方,例如:2/4/8/16/32/64/128...,而不能是中间的某个值.这是为什么呢? map是数组+链表的数据结构,读写数据都需要首先 ...
 - 数据结构解析-HashMap
		
概要 HashMap在JDK1.8之前的实现方式 数组+链表,但是在JDK1.8后对HashMap进行了底层优化,改为了由 数组+链表+红黑树实现,主要的目的是提高查找效率. 如图所示: JDK版本 ...
 - Leetcode - 剑指offer 面试题29:数组中出现次数超过一半的数字及其变形(腾讯2015秋招 编程题4)
		
剑指offer 面试题29:数组中出现次数超过一半的数字 提交网址: http://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163 ...
 - 为什么很多人坚信“富贵险中求”?
		
之家哥 2017-11-15 09:12:31 微信QQ微博 下载APP 摘要 网贷之家小编根据舆情频道的相关数据,精心整理的关于<为什么很多人坚信"富贵险中求"?>的 ...
 - 程序员必须知道的数据结构:HashMap 与 LinkedHashMap
		
为什么要说 HashMap 与 LinkedHashMap?第一:这两种数据结构是 Java Coder 中经常使用的数据结构.第二:这两种结构是最合适的能说明链表与数组的结构关系.在开始之前首先必须 ...
 - SQL SERVER中求上月、本月和下月的第一天和最后一天 DATEADD DATEDIFF
		
SQL SERVER中求上月.本月和下月的第一天和最后一天 1.上月的第一天 SELECT CONVERT(CHAR(10),DATEADD(month,-1,DATEADD(dd,-DAY(GE ...
 - 支付宝微信O2O大战,WiFi广告在夹缝中求生存
		
支付宝微信O2O大战,WiFi广告在夹缝中求生存 来自工信部的数据显示,截至2013年底,中国智能手机的保有量已经达到5.8亿台.国内平均有46%的时间选择WiFi上网. 商用WiFi已经成为了移动互 ...
 - MATLAB中求矩阵非零元的坐标
		
MATLAB中求矩阵非零元的坐标: 方法1: index=find(a); [i,j]=ind2sub(size(a),index); disp([i,j]) 方法2: [i,j]=find(a> ...
 
随机推荐
- FZU-2219 StarCraft(贪心)
			
Problem 2219 StarCraft Accept: 294 Submit: 860Time Limit: 1000 mSec Memory Limit : 32768 KB ...
 - 【bzoj1951】【古代猪文】Lucas定理+欧拉定理+孙子定理
			
(上不了p站我要死了,当然是游戏原画啊) Description (题面倒是很有趣,就是太长了) 题意: 一个朝代流传的猪文文字恰好为N的k分之一,其中k是N的一个正约数(可以是1和N).不过具体是哪 ...
 - reason: 'data parameter is nil'
			
最近APP启动之后老是报这个错:*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: ...
 - VisualStudio Shell简介 — 界面定制
			
项目组成 首先我们来看一下模板自动生成的工程文件: 它包括两个C++工程和两个C#工程,首先我们来看两个C++的工程: VSShellStub1, 这个是系统的启动项,它是最终的exe文件的 ...
 - Android 使用SQLite本地数据库
			
参考:http://blog.csdn.net/jianghuiquan/article/details/8569252 在Android平台上,集成了一个嵌入式关系型数据库—SQLite.以SQLi ...
 - 【Linux】Centos7安装之后,双系统的情况下,怎么能在CentOS7下访问Windows的磁盘
			
想要在CentOS7下访问Windows的NTFS格式的磁盘,需要在Linux下下载ntfs-3g步骤1: 进入root用户下,使用yum命令下载ntfs-3g.[前提是已经添加了常用源:http:/ ...
 - IMAP 命令
			
最近学习了一下IMAP命令,现在也算总结一下学习的东西,先说说IMAP命令,如果你使用的是163.126邮箱,反正是网易家的邮箱,那么这里就有很多坑要踩了,因为网易邮箱的特殊性,由于网易邮箱在中国占有 ...
 - 控制面板里找不到“应用程序server”这个项目,Windows XP中金蝶安装时无“应用程序server”的解决的方法
			
要注意先安装IIS,再安装VS2008. 我们会常常在控制面板里找不到"应用程序server"这个项目.我们须要依照以下的步骤来操作就会Ok. 1.下载IIS6,放置到D盘根文件夹 ...
 - java 文件上传数据库
			
存储文件的数据库类型: 1.oracle :Blob,bfile类型 2.mysql:longblob类型 3.sqlserver :varbinary(Max)类型 文件都是以二进制流存入数据库的, ...
 - ElasticSearch 排序
			
1.相关性排序 ElasticSearch为了按照相关性来排序,需要将相关性表示为一个数值,在 Elasticsearch 中, 相关性得分 由一个浮点数进行表示,并在搜索结果中通过 _score 参 ...