前言在閱讀hashmap原始碼時,會發現在hashmap中使用了紅黑樹,所以需要先了解什麼是紅黑樹,以及其原理。從而再進一步閱讀hashmap中的鍊錶到紅黑樹的轉換,紅黑樹的增刪節點等。
什麼是紅黑樹?在hashmap中是怎麼應用的?
紅黑樹(英語:red–black tree)是一種自平衡二叉查詢樹,是在電腦科學中用到的一種資料結構,典型的用途是實現關聯陣列。它在2023年由魯道夫·貝爾發明,被稱為"對稱二叉b樹",它現代的名字源於leo j. guibas和robert sedgewick於2023年寫的一篇**。紅黑樹的結構複雜,但它的操作有著良好的最壞情況執行時間,並且在實踐中高效:它可以在o(logn)時間內完成查詢、插入和刪除,這裡的n是樹中元素的數目。紅黑樹是每個節點都帶有顏色屬性的二叉查詢樹,顏色為紅色或黑色。在二叉查詢樹強制一般要求以外,對於任何有效的紅黑樹我們增加了如下的額外要求:
節點是紅色或黑色。
根是黑色。
所有葉子都是黑色(葉子是nil節點)。
每個紅色節點必須有兩個黑色的子節點。(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點。)
從任一節點到其每個葉子的所有簡單路徑都包含相同數目的黑色節點。
左旋、右旋
插入以二叉查詢樹的方法增加節點
新插入節點為紅色(如果設為黑色,就會導致根到葉子的路徑上有一條路上,多乙個額外的黑節點,這個是很難調整的。但是設為紅色節點後,可能會導致出現兩個連續紅色節點的衝突,那麼可以通過顏色調換(color flips)和樹旋轉來調整。)
注意:性質1和性質3是永遠保持著的。
性質4只在增加紅色節點、重繪黑色節點為紅色,或做旋轉時受到威脅。
性質5只在增加黑色節點、重繪紅色節點為黑色,或做旋轉時受到威脅。
插入時會遇到以下五種情形:
情形1:插入第乙個節點操作:插入第乙個節點情形2:插入新節點,父節點是黑色
情形3:插入新節點,父節點是紅色,叔父節點是紅色
情形4:插入新節點,父節點是紅色,叔父節點是黑色或缺省,新節點是右子節點,父節點又是其父節點的左子節點
情形5:插入新節點,父節點是紅色,叔父節點是黑色或缺省,新節點是左子節點,父節點又是其父節點的左子節點。
違反性質2:" 根是黑色。 "
情形:直接插入紅色節點,然後進行染色為黑色
操作:插入新節點,父節點是黑色
未違反性質
情形:直接插入
操作:插入新節點,父節點是紅色,叔父節點是紅色
違反性質4:" 每個紅色節點必須有兩個黑色的子節點。 "
情形:將祖父節點染色,祖父節點染色後再進行重新判斷進行染色或旋轉
操作:插入新節點,父節點是紅色,叔父節點是黑色或缺省,新節點是右子節點,父節點又是其父節點的左子節點
違反性質4:" 每個紅色節點必須有兩個黑色的子節點。 "
情形:進行左旋,旋轉後父節點變成左子節點,新節點變成父節點,然後重新判斷進行染色或旋轉
操作:插入新節點,父節點是紅色,叔父節點是黑色或缺省,新節點是左子節點,父節點又是其父節點的左子節點。
違反性質4:" 每個紅色節點必須有兩個黑色的子節點。 "
情形:父節點染色為黑色,進行右旋,祖父節點變為右子節點,然後重新判斷進行染色或旋轉
結構
static final class treenodeextends linkedhashmap.entry
三個引數/**
* 鍊錶轉為樹閾值。
* 大於等於8時,會轉換為樹。
* 8 是綜合性能考慮確定的值
*/static final int treeify_threshold = 8;
/** * 從樹轉換為鍊錶的閾值
*/static final int untreeify_threshold = 6;
/** * 最小樹形化容量,只有雜湊表元素數到達64才會進行樹轉換
*/static final int min_treeify_capacity = 64;
鍊錶轉紅黑樹-treeifybin
陣列(雜湊表)長度到達64
當鍊表長度大於等於8是會將鍊錶轉換為紅黑樹
final void treeifybin(node tab, int hash)
tl = p;
} while ((e = e.next) != null);
// 此時得到的僅僅是雙向鍊錶
// 指標指向煉表頭
if ((tab[index] = hd) != null)
// 將雙向鍊錶轉換為樹
hd.treeify(tab);}}
final void treeify(node tab)
else }}
}moveroottofront(tab, root);
}
// root 根節點
// x 要操作的節點
static treenodebalanceinsertion(treenoderoot, treenodex)
// 父節點黑色 或者 祖父節點為空,直接返回
// 情形2:插入新節點,父節點是黑色
else if (!xp.red || (xpp = xp.parent) == null)
return root;
// 父節點是祖父節點的左子節點
if (xp == (xppl = xpp.left))
// 旋轉
else
if (xp != null) }}
}// 父節點是祖父節點的右子節點
else
// 旋轉
else
if (xp != null) }}}}}
從HashMap看紅黑樹
樹上的節點要麼是紅色,要麼是黑色 根節點是黑色 每個葉子節點都是黑色的 所有的葉子節點都是null節點 紅色節點的子節點都是黑色的 任意乙個節點到其子孫葉子節點的黑色節點的數量是相等的。下面是乙個紅黑樹的圖示 從任意節點 不含該節點 到達乙個葉節點的任意一條簡單路徑上的黑色節點個數稱為該節點的黑高 ...
HashMap總結(不包括紅黑樹)
hashmap是用來存放key value的容器,底層是使用陣列 鍊錶 紅黑樹 實現的 節點少時 預設是untreeify threshold 6值 用鍊錶,多時 預設是 treeify threshold 8 用紅黑樹,樹化容量為min treeify capacity,預設是64。成員變數 構造...
漫畫 什麼是紅黑樹?
系列文章 漫畫 什麼是一致性雜湊?漫畫 什麼是b 樹?漫畫 什麼是b 樹?漫畫 什麼是跳躍表?漫畫 什麼是動態規劃?漫畫 當程式猿遇上智力測試題 漫畫 判斷 2 的乘方 漫畫演算法 最小棧的實現 漫畫 什麼是大資料?漫畫演算法 無序陣列排序後的最大相鄰差值 漫畫 什麼是bitmap演算法?漫畫 bi...