HashMap裡的一些知識點

2022-06-18 08:39:11 字數 1747 閱讀 7500

hashmap裡的k-v值如何計算得到索引:先看演算法如下,以jdk1.8為例:

int index = hash & (arrays.length-1);
hash為key的hashcode計算得到的,為什麼hashmap的陣列長度是2的整數冪呢,因為,以初始長度為16為例,16-1 = 15,15的二進位制數字00000000 00000000 00001111。可以看出乙個基數二進位制最後一位必然位1,當與乙個hash值進行與運算時,最後一位可能是0也可能是1。但偶數與乙個hash值進行與運算最後一位必然為0,造成有些位置永遠對映不上值。再來看看hash這個值如何得到:

static

final

inthash(object key)

上述這個演算法為了解決即使雜湊函式很鬆散,但只取最後幾位碰撞也會很嚴重的問題,這時候hash演算法的價值就體現出來了,hashcode右移16位,正好是32bit的一半。與自己本身做異或操作(相同為0,不同為1)。就是為了混合雜湊值的高低位,增加低位的隨機性。並且混合後的值也變相保持了高位的特徵。圖示如下:

原始碼解析如下:

//

說明,hashmap本次擴容之前,table不為null

if (oldtab != null

)

else

} while ((e = next) != null

);

if (lotail != null

)

if (hitail != null

) }}}

hashmap在樹化之後仍然保留了next節點,並且有pre節點指向鍊錶時上乙個元素,我們仍然可以按遍歷鍊錶的方式去遍歷上面的紅黑樹。這樣的結構為後面紅黑樹的切分以及紅黑樹轉成鍊錶做好了準備

紅黑樹在擴容時的split方法如下:

//

紅黑樹轉鍊錶閾值

static

final

int untreeify_threshold = 6;

final

void split(hashmapmap, node tab, int index, int

bit)

else

}if (lohead != null

) }

if (hihead != null

) }

}

擴容後,普通節點需要重新對映,紅黑樹節點也不例外。按照一般的思路,我們可以先把紅黑樹轉成鍊錶,之後再重新對映鍊錶即可。這種處理方式是大家比較容易想到的,但這樣做會損失一定的效率。不同於上面的處理方式,hashmap 實現的思路則很好。如上節所說,在將普通鍊錶轉成紅黑樹時,hashmap 通過兩個額外的引用 next 和 prev 保留了原鍊錶的節點順序。這樣再對紅黑樹進行重新對映時,完全可以按照對映鍊錶的方式進行。這樣就避免了將紅黑樹轉成鍊錶後再進行對映,無形中提高了效率。

重新對映後,會將紅黑樹拆分成兩條由 treenode 組成的鍊錶。如果鍊錶長度小於 untreeify_threshold,則將鍊錶轉換成普通鍊錶。否則根據條件重新將 treenode 鍊錶樹化。

一些知識點

字串拼接 1.a join b a為元素之間的分隔符,b為待分割的序列 可用於輸出時的資料處理,元素間有空格,末尾沒有 2 s s s str1,str2,str3 前半部分為字串,後半部分為索引。用於引入,s是物件 3.format str1,str2,str3 與f 括號裡為已有變數 關於for...

一些知識點

1.vector是在堆上還是棧上?在堆上.2.我們發現指標有一些 似是而非 的特徵 1 指標消亡了,並不表示它所指的記憶體會被自動釋放。比如函式中的指標是區域性變數,如果它指向了堆上,而自己出了函式後消亡了,但它所指向的記憶體還是存在的,導致了記憶體洩漏.2 記憶體被釋放了,並不表示指標會消亡或者成...

一些知識點

1 sln 解決方案檔案 csproj 專案檔案 cs 原始檔 解決方案包含多個專案,每個專案都是乙個程式。config 配置檔案 3 const int a 1 const 定義乙個量為常量,運算中用到當常量使用,不可以再重新賦值。4 型別轉換。1 隱式轉換。從值型別轉換成引用型別。從引用型別轉換...