您的位置:首页 > 职场人生

(2)面试 --- 在元素的装载数量明确的时候HashMap的大小应该如何选择 || 二维数组打印对角线

2015-05-05 09:10 597 查看
今天看到美团招聘给出了一道小题目,关于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 }

{ 5 6 7 8 }

{ 9 10 11 12 }

{13 14 15 16 }

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.csdn.net/liuwei063608/article/details/27342123
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐