今天看到美团招聘给出了一道小题目,关于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
原文地址:点击打开链接 http://www.cnblogs.com/coderxuyang/p/3718856.html
===================================================================================================================
1,二维数组(N*N),沿对角线方向,从右上角打印到左下角如N=4: 4*4二维数组
{ 1 2 3 4 }
4
3 8
2 7 12
1 6 11 16
5 10 15
9 14
13
主要是要找到数组下标的规律,先考虑一共生成几组结果,然后找到每组结果的规律
//规律是第 K的 列号-行号=size-1-k
{ 1 2 3 4 }
{ 5 6 7 8 }
{ 9 10 11 12 }
{13 14 15 16 } 2*4-1 行 列 列 -行 = len长度-第几行
4 1 03 3-0 = 4 - 1
3 8 2 02 13 2 = 4 - 2
2 7 12 3 01 12 23 1 = 4 - 3
1 6 11 16 4 00 11 22 33 0 = 4 - 4
5 10 15 5 10 21 32 -1 = 4 - 5
9 14 6 20 31 -2 = 4 - 6
13 7 30 -3 = 4 - 7
/**
* Description:二维数组(N*N),沿对角线方向,从右上角打印到左下角
* @author liuwei DateTime 2014-5-27 下午4:13:56
* @param args
*/
public static void main(String[] args) {
int[][] a = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,16}};
// int[][] a = {{1,2,3},
// {4,5,6},
// {7,8,9}};
int size = a.length;
int len = 2*a.length-1;//一共生成几行结果
for(int k=0;k<len;k++){
//规律是第 K的 列号-行号=size-1-k
for(int i=0;i<size;i++){
for(int j=0;j<size;j++){
if(j-i == size-1-k){
System.out.print(a[i][j]+" ");
}
}
}
System.out.println("");
}
}
转载地址:点击打开链接 http://blog.youkuaiyun.com/liuwei063608/article/details/27342123