在元素的装载数量明确的时候HashMap的大小应该如何选择。
今天看到美团招聘给出了一道小题目,关于HashMap的性能问题。问题如下:
java hashmap,如果确定只装载100个元素,new HashMap(?)多少是最佳的,why?
要回答这个问题,首先得知道影响HashMap性能的参数有哪些。咱们翻翻JDK。
在JDK6中是这么描述的:
HashMap的实例有两个参数影响其性能:初始容量和加载因子。
首先我们来看初始容量和加载因子的定义。
容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。
加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。
当哈希表中条目的数目超过 容量乘加载因子 的时候,则要对该哈希表进行rehash操作,从而哈希表将具有大约两倍的桶数。(以上摘自JDK6)
HashMap默认的加载因子是0.75 .它在时间和空间成本上寻求了一种折中。
回到本文的问题。根据JDK中的描述,如果这个只装载100个元素的HashMap没有特殊的用途,那么为了在时间和空间上达到最佳性能,HashMap的初始容量可以设为
100/0.75 = 133.33。为了防止rehash,向上取整,为134。
但是还有另外一个问题,就是hash碰撞的问题。如果我们将HashMap的容量设置为134,那么如何保证其中的哈希碰撞会比较少呢?
除非重写hashcode()方法,否则,似乎没有办法保证。
那么这里不得不提HashMap如何为元素选择下标的方法了。
static int indexFor(int h, int length) {
return h & (length-1);
}
其中h为key哈希后得到的值,length为哈希表的长度。
134-1 = 128 + 6 -1;
那么 length-1的二进制值的最后3位为101;
假设这100个装载的元素中他们的key在哈希后有得到两个值(h),他们的二进制值除了低3位之外都相同,而第一个值的低3位为011,第二个值的低3位为001;
这时候进行java的&预算,011 & 101 = 001 ;001 & 101 = 001;
他们的值相等了,那么这个时候就会发生哈希碰撞。
除此之外还有一个更加严重的问题,由于在101中第二位是0,那么,无论我们的key在哈希运算之后得到的值h是什么,那么在&运算之后,得到的结果的倒数第二位均为0;
因此,对于hash表所有下标的二进制的值而言,只要低位第二位的值为1,(例如0010,0011,0111,1111)那么这个下标所代表的桶将一直是空的,因为代码中的&运算的结果永远不会产生低位第二位为1的值。这就大大地浪费了空间,同时还增加了哈希碰撞的概率。这无疑会降低HashMap的效率。
那么如何才能减少这种浪费呢?最佳的方法当然是让length-1的二进制值全部位均为1.那么length的值是多少合适呢?
没错,length=2^n。
只要将hash表的长度设为2的N次方,那么,所有的哈希桶均有被使用的可能。
再次回到美团提出的问题,与134最靠近的2^n无疑是128。
如果只修改HashMap的长度而不修改HashMap的加载因子的话,HashMap会进行rehash操作,这是一个代价很大的操作,所以不可取。
那么应该选择的就应该是256。
而由于空间加大和有效利用哈希桶,这时的哈希碰撞将大大降低,因此HashMap的读取效率会比较高。
所以,最后结论就是:HashMap的大小应该设置为256。
结果的补充:其实在Java中,无论你的HashMap(x)中的x设置为多少,HashMap的大小都是2^n。2^n是大于x的第一个数。因为HashMap的初始化代码中有以下这行代码:
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
但是这就带来了一个问题,如果x=100,那么HashMap的初始大小应该是128.但是100/128=0.78,已经超过默认加载因子的大小了。因此会resize一次,变成256。所以最好的结果还是256。
最后发个参考链接:http://www.iteye.com/topic/539465
在元素的装载数量明确的时候HashMap的大小应该如何选择。的更多相关文章
- 对JSON数组对象排序-有键相同的元素,分组数量不一致,可采用如下的JS进行循环表格输出
var now=eval(data.data); // now.sort(sortBy('bigIdOrder', true, parseInt)); var tab=""; va ...
- c++ 容器元素填充指定数量的元素(generate_n)
#include <iostream> // cout #include <algorithm> // generate_n using namespace std; ; in ...
- 前端性能优化---减少http请求数量和减少请求资源的大小
减少http请求数量:就是资源的合并 减少http请求大小:就是资源的压缩 一.资源合并的原理: 资源不合并的缺点: 1.文件和文件之间有插入请求----请求a.js,b.js,c.js(三行 ...
- 将一个整数数组先按照因子数量排序,再按照数字大小排序,输出第k个数
同小米OJ比赛题:现在有 n 个数,需要用因子个数的多少进行排序,因子个数多的排在后面,因子个数少的排在前面,如果因子个数相同那么就比较这个数的大小,数大的放在后面,数小的放在前面.现在让你说出排序之 ...
- java 代码
java 里的 pandas tablesaw DataFrame 再有就是 spark 了 java 代码规范 Java8特性详解 lambda表达式 Stream Sonar 规则检测 sprin ...
- 关于HashMap初始化容量问题
使用阿里云代码规范插件扫描后出现以下提示: hashmap should set a size when initalizing,即hashmap应该在初始化时设置一个大小 在网上搜到一篇讲解(htt ...
- Java集合类源码解析:HashMap (基于JDK1.8)
目录 前言 HashMap的数据结构 深入源码 两个参数 成员变量 四个构造方法 插入数据的方法:put() 哈希函数:hash() 动态扩容:resize() 节点树化.红黑树的拆分 节点树化 红黑 ...
- Java基础知识点3:集合类
集合类是Java编程中经常会用到的一类常用类库,在这里将会对整个集合类进行介绍: Collection接口: Collection接口是所有集合类的根接口,代表了所有含有多个元素的集合,无论这个集合中 ...
- 堆--P1168 中位数
题目描述 给出一个长度为N的非负整数序列Ai,对于所有1≤k≤(N+1)/2,输出A1,A3,…,A2k−1的中位数.即前1,3,5,…个数的中位数. 输入格式 第1行为一个正整数N,表示了序列长度 ...
随机推荐
- JAVA常见算法题(三十)
package com.forezp.util; import java.io.BufferedReader; import java.io.FileReader; import java.io.In ...
- easyui 后台系统引入富文本编辑器的使用
1.首先,想在项目中引入相关的jar包 2.html页面中加入相关的引用 <!-- kindeditor --> <script type="text/javascript ...
- unity3d由多个部分组成一个角色
摘自http://forum.unity3d.com/threads/16485-quot-stitch-multiple-body-parts-into-one-character-quot So ...
- iOS:菜单控制器和菜单项:UIMenuController和UIMenuItem
菜单控制器和菜单项:弹出自定义的菜单栏窗口 提示: 1. Menu所处的View必须实现 – (BOOL)canBecomeFirstResponder, 且返回YES2. Menu所处的View必须 ...
- java 注解(自身理解)
声明注解 使用注解 解析注解 产生的结果 注解利用的是反射机制 ============================================================= 使用注解修饰 ...
- 我的Android进阶之旅------>Android关于TextWatcher的初步了解
首先来看一下TextWatcher的源码 package android.text; /** * When an object of a type is attached to an Editable ...
- WebService 之 协议篇
Web Service 使用的是 SOAP (Simple Object Access Protocol)简单对象访问协议,是交换数据的一种协议规范,是一种轻量的.简单的.基于XML(标准通用标记语言 ...
- ffmpeg代码解析
void avdevice_register_all(void){ static int initialized; if (initialized) return; i ...
- 01-hibernate注解:类级别注解,@Entity,@Table,@Embeddable
@Entity @Entity:映射实体类 @Entity(name="tableName") name:可选,对应数据库中一个表,若表名与实体类名相同,则可以省略. 注意:使用@ ...
- c# webbrowser 清除cookie和缓存
由于缓存文件是特殊的文件,以及WebBrowser与IE版本有关因此删除缓存绝对不可能用一些IO函数就总可以解决的因此我的这些函数在IO操作的基础上,又针对环境进行相应的清理. static clas ...