(2)面試 --- 在元素的裝載數量明確的時候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

原文地址:點擊打開鏈接 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

發佈了55 篇原創文章 · 獲贊 4 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章