element 往node里面增加属性值_HashMap加载因子为何0.75,为何初始化值2的指数幂,底层解析...
01
前言
我們在聲名HashMap的時候,一般都會這樣寫。
public class MapTest {
public static void main(String[] args) {
HashMapmap=new HashMap<>();
}
}
我們不會向里面加入初始容量,它自己會給我們一個初始化的容量,一般是16。
大家有沒有看過hashmap的底層,java7版本是數(shù)組加鏈表
1.8之后引入紅黑樹。性能提升百分之十到到百分之15左右。
02
加載因子為何0.75
HashMap有兩個參數(shù)影響其性能:初始容量和加載因子。容量是哈希表中桶的數(shù)量,初始容量只是哈希表在創(chuàng)建時的容量。加載因子是哈希表在其容量自動擴(kuò)容之前可以達(dá)到多滿的一種度量。當(dāng)哈希表中的條目數(shù)超出了加載因子與當(dāng)前容量的乘積時,則要對該哈希表進(jìn)行擴(kuò)容、rehash操作(即重建內(nèi)部數(shù)據(jù)結(jié)構(gòu)),擴(kuò)容后的哈希表將具有兩倍的原容量。
通常,加載因子需要在時間和空間成本上尋求一種折衷。
加載因子過高,例如為1,雖然減少了空間開銷,提高了空間利用率,但同時也增加了查詢時間成本;
加載因子過低,例如0.5,雖然可以減少查詢時間成本,但是空間利用率很低,同時提高了rehash操作的次數(shù)。
在設(shè)置初始容量時應(yīng)該考慮到映射中所需的條目數(shù)及其加載因子,以便最大限度地減少rehash操作次數(shù),所以,一般在使用HashMap時建議根據(jù)預(yù)估值設(shè)置初始容量,減少擴(kuò)容操作。
選擇0.75作為默認(rèn)的加載因子,完全是時間和空間成本上尋求的一種折衷選擇。
03
為何初始化值2的指數(shù)冪
1.奇數(shù)不行的解釋很能被接受,在計(jì)算hash的時候,確定落在數(shù)組的位置的時候,計(jì)算方法是(n - 1) & hash ,奇數(shù)n-1為偶數(shù),偶數(shù)2進(jìn)制的結(jié)尾都是0,經(jīng)過&運(yùn)算末尾都是0,會
增加hash沖突
2.為啥要是2的冪,不能是2的倍數(shù)么,比如6,10?
2.1 hashmap 結(jié)構(gòu)是數(shù)組,每個數(shù)組里面的結(jié)構(gòu)是node(鏈表或紅黑樹),正常情況下,如果你想放數(shù)據(jù)到不同的位置,肯定會想到取余數(shù)確定放在那個數(shù)據(jù)里, ?計(jì)算公式:
hash % n,這個是十進(jìn)制計(jì)算。在計(jì)算機(jī)中, ?(n - 1) & hash,當(dāng)n為2次冪時,會滿足一個公式:(n - 1) & hash = hash % n,計(jì)算更加高效。
2.2 只有是2的冪數(shù)的數(shù)字經(jīng)過n-1之后,二進(jìn)制肯定是 ?...11111111 ?這樣的格式,這種格式計(jì)算的位置的時候,完全是由產(chǎn)生的hash值類決定,而不受n-1 影響。你可能會想,
受影響不是更好么,又計(jì)算了一下 ,hash沖突可能更低了,這里要考慮到擴(kuò)容了,2的冪次方*2,在二進(jìn)制中比如4和8,代表2的2次方和3次方,他們的2進(jìn)制結(jié)構(gòu)相 似,比如
4和8 ? 00000100 ? ?0000 1000 ? 只是高位向前移了一位,這樣擴(kuò)容的時候,只需要判斷高位hash,移動到之前位置的倍數(shù)就可以了,免去了重新計(jì)算位置的運(yùn)算。
04
紅黑樹定義
通過源碼解析,我們已經(jīng)很清楚HashMap是在“當(dāng)鏈表已經(jīng)有8個節(jié)點(diǎn)了,此時再新鏈上第9個節(jié)點(diǎn),在成功添加了這個新節(jié)點(diǎn)之后,立馬做鏈表轉(zhuǎn)紅黑樹
定義:紅黑樹是一種自平衡的二叉查找樹,是一種高效的查找樹。紅黑樹有良好的效率,它可以在時間復(fù)雜度為O(logN)時間內(nèi)完成查找 增加 刪除等操作。
性質(zhì):
1.根是黑色
2.節(jié)點(diǎn)是紅色或者黑色
3.所有的葉子都是黑色的(葉子是NIL節(jié)點(diǎn))
4. 每個紅色節(jié)點(diǎn)必須有兩個黑色的子節(jié)點(diǎn)
5. 從任一節(jié)點(diǎn)到其每個葉子的所有簡單路徑都包含相同數(shù)目的黑色節(jié)點(diǎn)。
05
二叉樹查找
public class BST, Value> {
private Node root;
class Node {
Key key;
Value value;
Node left, right;//左右子結(jié)點(diǎn)
int N;//以該結(jié)點(diǎn)為父結(jié)點(diǎn)的所有子結(jié)點(diǎn)的數(shù)量
public Node(Key key, Value value, int N) {
this.key = key;
this.value = value;
this.N = N;
}
}
public void put(Key key, Value value) {
root=put(root,key,value);
}
/**
* 先遞歸向下尋找key所在的位置,如果有則更新對應(yīng)的value,
* 如果沒有,當(dāng)在樹的底部添加了一個新結(jié)點(diǎn)之后,還需要
* 從下往上更新所有父結(jié)點(diǎn)的N的值。
*/
private Node put(Node node, Key key, Value value) {
if (node==null){
return new Node(key,value,1);
}
int cmp=key.compareTo(node.key);
if (cmp<0) {
node.left=put(node.left,key,value);
}else if (cmp>0){
node.right= put(node.right,key,value);
}else {
node.value=value;
}
node.N=size(node.left)+size(node.right)+1;
return node;
}
public Value get(Key key) {
return get(root, key);
}
/**
* 使用遞歸的方式,從根節(jié)出發(fā),不斷向下查找
*/
private Value get(Node node, Key key) {
if (node == null) {
return null;
}
int cmp = key.compareTo(node.key);
if (cmp < 0) {
return get(node.left, key);
} else if (cmp > 0) {
return get(node.right, key);
} else {
return node.value;
}
}
public int size() {
return size(root);
}
public int size(Node node) {
if (node == null) return 0;
return node.N;
}
}
總結(jié)
以上是生活随笔為你收集整理的element 往node里面增加属性值_HashMap加载因子为何0.75,为何初始化值2的指数幂,底层解析...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win10清理垃圾指令代码是什么
- 下一篇: fgo猛兽特性的敌人是谁(如何在pc端下