對hashMap的初步理解

2021-09-29 19:22:30 字數 3076 閱讀 1603

當我們建立乙個hashmap,往hashmap裡面put元素的時候,hashmap內部會建立乙個陣列,陣列如果不指定初始容量,那麼hashmap在建立物件時,在第一次put元素的時候會預設指定乙個陣列的初始長度,為16位

static

final

int default_initial_capacity =

1<<4;

// aka 16

將元素節點的key換算成hashcode,hashcode通過乙個hash值的計算,計算出來乙個具體的索引下標index的位置,然後將put進來的元素放入到對應的索引處

static

final

inthash

(object key)

進行hash計算的時候需要進行位擾動,進行位擾動的目的是讓結點在陣列中分散均勻,每乙個索引盡量不空著,在不浪費記憶體的同時提公升查詢效率,如果只進行取模運算而不進行位的干擾,會導致有些索引沒有存值,有的索引下的鍊錶已經很長了,大大降低查詢效率。jdk8以後hashmap底層資料結構為:hash表 = 陣列+鍊錶+紅黑樹,計算hash值的時候進行位干擾,可以讓索引下的鍊錶盡量短一點,發揮每乙個資料結構的優點,陣列結構,鍊錶結構,以及紅黑樹的結構,將這些優點集中起來從而使得hashmap擁有很高的效率。

int hash = hash(key);,

為什麼不直接用hashcode取模,而要用hash去算hash值?當hashmap容量比較大的時候,會產生比較多的hash碰撞, hash函式在運算(即通過hashcode計算索引下標存放位置的時候)的時候,每個字串或者物件會產生雜湊碰撞,產生雜湊碰撞會導致計算出來的大量的索引位置重複,重複之後會產生大量雜湊碰撞,會導致鍊錶變長,get值的時候查詢效能降低,所以在hash值裡面會將拿到的hashcode進行一系列的位干擾/位擾動(異或或者位移運算)儘量減少雜湊碰撞,減少查詢元素的時間複雜度。

陣列儲存特點:使用陣列儲存的時候,使用一段連續儲存單元儲存資料,對於指定下標的查詢時間複雜度為o(1)

hashmap

hashmap =

newhashmap

(13);

hashmap.

put(

"波妞"

,"宗介"

);

假設對key求hash值:

h = 「波妞」.hashcode的值為:

0000 0000 0000 1101 0001 0101 0101 1111

length的初始長度為16

h >>> 16:

0000 0000 0000 0000 0000 0000 0000 1101

hash = h^(h>>>16):0000 0000 0000 1101 0001 0101 0101 1111

n = 16 - 1 :0000 0000 0000 0000 0000 0000 0000 1111

做與運算即可得出十進位制的索引值。

切記lengh的初始長度為16(10000),如果不減1,無論上面的hashcode值怎樣變化都會導致與出來的十進位制結果為0或者16,此時會導致索引下標為1~14永遠為空舉個例子:

hash: 1010 1111

length: 0001 0000 此時與出來的結果為0,則會導致put進來的元素永遠存入0索引處

hash: 1011 1111

length: 0001 0000 此時與出來的結果為1,則會丟擲索引越界異常。

public v put

(k key, v value)

put過程:

1.對key求hash值,然後在計算下標。

2.如果沒有碰撞,直接放入桶中,

3.如果碰撞了,以鍊錶的方式鏈結在後面

4.如果結點已經存在就替換舊值

5.如果桶滿了(容量*載入因子),進行resize

final v putval

(int hash, k key, v value,

boolean onlyifabsent,

boolean evict)

if(e.hash == hash &&

((k = e.key)

== key ||

(key != null && key.

equals

(k))))

break

; p = e;}}

if(e != null)

}++modcount;if(

++size > threshold)

resize()

;afternodeinsertion

(evict)

;return null;

}

往hashmap裡面put元素的時候,當put進來的新元素經過hash運算,得出的index值的位置已經存在節點元素了,jdk7處理方式:先校驗該索引處已經存在的結點元素或者已經在該索引處形成鍊錶的所有元素的key值是否有重複的,逐一比對做校驗,校驗完成後若沒有重複的key值,則新put進來的結點元素形成乙個指標指向陣列元素上計算出來索引位置的結點,相對應地在頭部去插入,不會乙個乙個地遍歷插入在鍊錶的尾部,在插入結點之前做校驗的時候已經將整個鍊錶遍歷了,遍歷的目的就是為了避免key值重複,避免新put進來元素的key值是在這個煉表裡已經存在的key,若已經存在會用新值替換舊值)jdk8以後,新put進來的結點元素會用它的鍵值對與已經存在的元素的鍵值對做比對,比對後如果新put進來的key值和已經存在的結點元素的key值相同,則會用新的value值覆蓋掉舊的value值,如果key值不同,則會判斷已經存在的結點下的資料結構是紅黑樹還是鍊錶,如果是紅黑樹則會把新put進來的結點插入到紅黑樹中,往紅黑樹裡面插入元素會破壞紅黑樹的平衡性,此時需要經過樹旋轉以及著色來重新維護紅黑樹的平衡性,如果資料結構沒有達到紅黑樹的級別則會在原有結點的基礎上形成一條鍊錶,當鍊表的資料結構長度超過8的時候會轉換成紅黑樹,因為鍊錶對於查詢操作需要遍歷鍊錶中的所有結點逐一進行對比,複雜度為o(n)。

為什麼每次size++的時候modcount的值也會加加?

對HashMap的初步理解

一 hashmap 1 用來儲存key value鍵值對的一種結構 2 底層由陣列 鍊錶實現 二 hash和map的理解 1 雜湊hash 雜湊演算法也叫雜湊演算法,就是把任意長度值 key 通過雜湊演算法變換成固定長度的key位址,通過這個位址進行訪問的資料結構。它通過把關鍵碼值對映到表中乙個位置...

對Spring初步理解

spring 實現宣告式事務方法一 xmlns xmlns xsi xmlns aop xmlns tx xsi schemalocation spring beans 2.5.xsd spring tx 2.5.xsd spring aop 2.5.xsd 步驟 1.配置aop 切入範圍 exec...

我對tcp的初步理解

以前總聽說tcp ip協議,感覺很叼,總搞不清是個什麼東西。最近在看unix網路程式設計,似乎有點懂了,不就是源 麼。也就是核心的一部分,至於是誰規定出來的,是誰寫出來的,我想應該是n個牛人協議出來的吧。以前看書的時候總有這樣的問題,為什麼有了tcp就可以實現網路的資料傳輸呢?是不是我有點sb 現在...