通過以下**開始
static
final
inttablesizefor
(int cap)
|=(或等於):這個符號比較少見,但是「+=」應該都見過,看到這你應該明白了。例如:a |= b ,可以轉成:a = a | b。
假設 n 的值為 0010 0001,則該計算如下圖:
hashmap 的容量必須是 2 的 n 次方,這是為什麼?計算索引位置的公式為:(n - 1) & hash,當 n 為 2 的 n 次方時,n - 1 為低位全是 1 的值,此時任何值跟 n - 1 進行 & 運算的結果為該值的低 n 位,達到了和取模同樣的效果,實現了均勻分布。實際上,這個設計就是基於公式:x mod 2^n = x & (2^n - 1),因為 & 運算比 mod 具有更高的效率。
如下圖,當 n 不為 2 的 n 次方時,hash 衝突的概率明顯增大。
^運算子跟 | 類似,但有一點不同的是 如果兩個操作位都為1的話,結果產生00 1 0 0 0 0 0 1
0 1 0 1 1 0 1 0
產生 0 0 0 1 1 0 1 1
通過hash算法定位元素在陣列中的位置整個過程本質上就是三步:拿到 key 的 hashcode 值static
final
inthash
(object key)
// 真正定位到元素在陣列中的位置
n = tab.length;
i =(n -1)
& hash
將 hashcode 的高位參與運算,重新計算 hash 值
將計算出來的 hash 值與 (table.length - 1) 進行 & 運算
x mod 2^n=x&(2 ^ n-1)
那在什麼時候用鍊錶?什麼時候用紅黑樹?任何數對乙個指定的數字進行取模,結果總會落在[0,指定的數字之間]。。。對於插入,預設情況下是使用鍊錶節點。當同乙個索引位置的節點在新增後達到9個(閾值8):如果此時陣列長度大於等於 64,則會觸發鍊錶節點轉紅黑樹節點(treeifybin);而如果陣列長度小於64,則不會觸發鍊錶轉紅黑樹,而是會進行擴容,因為此時的資料量還比較小。
對於移除,當同乙個索引位置的節點在移除後達到 6 個,並且該索引位置的節點為紅黑樹節點,會觸發紅黑樹節點轉鍊錶節點(untreeify)
如果我們設定節點多於8個轉紅黑樹,少於8個就馬上轉鍊錶,當節點個數在8徘徊時,就會頻繁進行紅黑樹和鍊錶的轉換,造成效能的損耗
HashMap位運算你可知一二
我們平時在寫 過程中用的位運算操作比較少,因為我們更關注於可讀性而不是效能,如果為了效能而使用較多的位運算,我想我們的同事會瘋掉。但在框架里位運算卻非常常見,因為框架的效能是我們關注的點。下面就來一起回顧一下常見的位運算操作 左移運算子,num 1,相當於num乘以2 低位補0 表示右移,如果該數為...
異或運算 HashMap位運算你可知一二
我們平時在寫 過程中用的位運算操作比較少,因為我們更關注於可讀性而不是效能,如果為了效能而使用較多的位運算,我想我們的同事會瘋掉。但在框架里位運算卻非常常見,因為框架的效能是我們關注的點。下面就來一起回顧一下常見的位運算操作 左移運算子,num 1,相當於num乘以2 低位補0 表示右移,如果該數為...
LeetCode之位運算
public intadd int a,int b return a 劍指offer 64 求1 2 n 難度 中等 求 1 2 n 要求不能使用乘除法 for while if else switch case等關鍵字及條件判斷語句 a?b c 題解 用遞迴的方法的 public intsumnu...