日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HashMap与加载因子/负载因子loadFactor关系

發布時間:2025/3/20 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HashMap与加载因子/负载因子loadFactor关系 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

HashMap以<key,value>的方式存放數據,存儲在數組中。通過開散列方法解決沖突,數組中存放的Entry作為單向鏈表的表頭。

Entry的源碼如下:

static class Entry<K,V> implements Map.Entry<K,V> {final K key;V value;Entry<K,V> next;final int hash;//構造、get、set等方法省略public final boolean equals(Object o) {if (!(o instanceof Map.Entry))return false;Map.Entry e = (Map.Entry)o;Object k1 = getKey();Object k2 = e.getKey();if (k1 == k2 || (k1 != null && k1.equals(k2))) {Object v1 = getValue();Object v2 = e.getValue();if (v1 == v2 || (v1 != null && v1.equals(v2)))return true;}return false;}public final int hashCode() {return (key==null ? 0 : key.hashCode()) ^(value==null ? 0 : value.hashCode());}}

下面我們通過走讀源碼來逐步探索HashMap的奧秘!!!

一)“發現問題,存有疑問!”

1)構造HashMap中的capacity

capacity為當前HashMap的Entry數組的大小,為什么Entry數組的大小是2的N次方?

// Find a power of 2 >= initialCapacity int capacity = 1; while (capacity < initialCapacity)capacity <<= 1;

2)構造HashMap中的loadFactor(裝填因子)

threshold = (int)(capacity * loadFactor);

threshold為HashMap的size最大值,注意不是HashMap內部數組的大小。

為什么需要loadFactor,怎么合理的設置loadFactor?

3)HashMap的put

public V put(K key, V value) {if (key == null)return putForNullKey(value);//當key為null時,將其存放在數組的首部:table[0]int hash = hash(key.hashCode());int i = indexFor(hash, table.length);for (Entry<K,V> e = table[i]; e != null; e = e.next) {Object k;if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}modCount++;addEntry(hash, key, value, i);return null; }

這里我們關注兩個地方:

1)hash

static int hash(int h) {// This function ensures that hashCodes that differ only by// constant multiples at each bit position have a bounded// number of collisions (approximately 8 at default load factor).h ^= (h >>> 20) ^ (h >>> 12);return h ^ (h >>> 7) ^ (h >>> 4);}

hash的作用是什么?

2)indexFor

static int indexFor(int h,int length) {return h & (length-1);}

indexFor的作用是什么?

二)“解惑,撥云見日!”

key的hashCode經過hash后,為了讓其在table(table為hashMap的entry[])的范圍內,需要再hash一次。這里實際上是采用的“除余法”(h%length)。

源于一個數學規律,就是如果length是2的N次方,那么數h對length的模運算結果等價于a和(length-1)的按位運算,也就是?h%length?<=> h&(length-1)。

位運算當然比取余效率高,因此這就解釋了:為什么Entry數組的大小是2的N次方?

我們為什么不直接對key的hashCode進行indexFor運算,還要再hash一次呢?

我做了個簡單實驗,如下:

int[] hashcode = new int[] { 100000001,100000011,100000111,100001111,100011111,100111111,101111111,111111111 }; for (int c : hashcode)System.out.println(hash(c));

數組hashcode中假定了8個hashcode,若對他們除以10取余,余數都為1,全部沖突!

但是通過hash后,對應的值為:

94441116; 94441110; 94441204; 94440071; 94558923; 94592891; 107664244; 117165177

對上面的值除以10取余分別是:6、0、4、1、3、1、4、7,沖突為2。

可見hash能夠對hashCode分布更均勻,防止一些蹩腳的hash函數!

從上面我們也可以看出取余的時候,高位的影響比較小,例如:1048592、1048832、1052672、1114112、2097152都可以被16整除(余數為0)!

那么我們得想個辦法讓高位也要影響到取余的結果,如是便有了Hash。

詳情參考:http://marystone.iteye.com/blog/709945

對于loadFactor,我也做了個簡單實驗,如下:

public static void main(String[] args) {String s = "a aa aaa b bb bbb c cc ccc d dd ddd e ee eee f ff fff g gg ggg h hh hhh abc bcd cde def efg fgh ghi hij ijk ";String[] ss = s.split(" ");int size = ss.length;//Set<Integer> indexS = new HashSet<Integer>();int conflict = 0;for (int i = 0; i < ss.length; i++) {int index = hash(ss[i].hashCode()) % size;if (indexS.contains(index))conflict++;elseindexS.add(index);}System.out.println("沖突數:"+conflict);}

當參與取余的除數為size時,沖突數為13

當參與取余的除數為2*size時,沖突數為9

當參與取余的除數為3*size時,沖突數為6

在hashMap中,size受loadFactor的影響。

極端的想,

如果loadFactor很小很小,那么map中的table需要不斷的擴容,導致除數越來越大,沖突越來越小!

如果loadFactor很大很大,那么當map中table放滿了也不要求擴容,導致沖突越來越多,解決沖突而起的鏈表越來越長!

原文鏈接:http://www.cnblogs.com/huangfox/archive/2012/07/06/2579614.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的HashMap与加载因子/负载因子loadFactor关系的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。