今天看到美團招聘給出了一道小題目,關於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.csdn.net/liuwei063608/article/details/27342123