JDK1.8最重要的就是引入了紅黑樹的設計(當衝突的鏈表長度超過8個的時候),爲何要這樣設計呢?好處就是避免在最極端的狀況下衝突鏈表變得很長很長,在查詢的時候,效率會很是慢。性能
本文主要是講解紅黑樹的實現,只有充分理解了紅黑樹,對於後面的分析纔會更加順利。設計
簡單的說,紅黑樹是一種近似平衡的二叉查找樹,其主要的優勢就是「平衡「,即左右子樹高度幾乎一致,以此來防止樹退化爲鏈表,經過這種方式來保障查找的時間複雜度爲log(n)。3d
關於紅黑樹的內容,網上給出的內容很是多,主要有如下幾個特性:指針
在樹的結構發生改變時(插入或者刪除操做),每每會破壞上述條件3或條件4,須要經過調整使得查找樹從新知足紅黑樹的條件。code
上面已經說到當樹的結構發生改變時,紅黑樹的條件可能被破壞,須要經過調整使得查找樹從新知足紅黑樹的條件。blog
調整能夠分爲兩類:一類是顏色調整,即改變某個節點的顏色,這種比較簡單,直接將節點顏色進行轉換便可;另外一類是結構調整,改變檢索樹的結構關係。結構調整主要包含兩個基本操做:左旋(Rotate Left),右旋(RotateRight)。get
左旋的過程是將p的右子樹繞p逆時針旋轉,使得p的右子樹成爲p的父親,同時修改相關節點的引用,使左子樹的深度加1,右子樹的深度減1,經過這種作法來調整樹的穩定性。過程以下:源碼
以jdk1.8爲例,打開HashMap的源碼部分,紅黑樹內部類TreeNode屬性分析:class
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> { //指向父節點的指針 TreeNode<K,V> parent; //指向左孩子的指針 TreeNode<K,V> left; //指向右孩子的指針 TreeNode<K,V> right; //前驅指針,跟next屬性相反的指向 TreeNode<K,V> prev; //是否爲紅色節點 boolean red; ...... }
左旋方法rotateLeft以下:效率
/* * 左旋邏輯 */ static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root, TreeNode<K,V> p) { //root:表示根節點 //p:表示要調整的節點 //r:表示p的右節點 //pp:表示p的parent節點 //rl:表示p的右孩子的左孩子節點 TreeNode<K,V> r, pp, rl; //r判斷,若是r爲空則旋轉沒有意義 if (p != null && (r = p.right) != null) { //多個等號的鏈接操做從右往左看,設置rl的父親爲p if ((rl = p.right = r.left) != null) rl.parent = p; //判斷p的父親,爲空,爲根節點,根節點的話就設置爲黑色 if ((pp = r.parent = p.parent) == null) (root = r).red = false; //判斷p節點是左兒子仍是右兒子 else if (pp.left == p) pp.left = r; else pp.right = r; r.left = p; p.parent = r; } return root; }
瞭解了左旋轉以後,相應的就會有右旋,邏輯基本也是同樣,只是方向變了。右旋的過程是將p的左子樹繞p順時針旋轉,使得p的左子樹成爲p的父親,同時修改相關節點的引用,使右子樹的深度加1,左子樹的深度減1,經過這種作法來調整樹的穩定性。實現過程以下:
一樣的,右旋方法rotateRight以下:
/* * 右旋邏輯 */ static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root, TreeNode<K,V> p) { //root:表示根節點 //p:表示要調整的節點 //l:表示p的左節點 //pp:表示p的parent節點 //lr:表示p的左孩子的右孩子節點 TreeNode<K,V> l, pp, lr; //l判斷,若是l爲空則旋轉沒有意義 if (p != null && (l = p.left) != null) { //多個等號的鏈接操做從右往左看,設置lr的父親爲p if ((lr = p.left = l.right) != null) lr.parent = p; //判斷p的父親,爲空,爲根節點,根節點的話就設置爲黑色 if ((pp = l.parent = p.parent) == null) (root = l).red = false; //判斷p節點是右兒子仍是左兒子 else if (pp.right == p) pp.right = l; else pp.left = l; l.right = p; p.parent = l; } return root; }
至此,紅黑樹的實現就基本完成了,關於紅黑樹的結構,有不少種狀況,狀況也比較複雜,可是總體調整流程,基本都是先調整結構而後調整顏色,直到最後知足紅黑樹特性要求爲止。整篇文章,若是有理解不當之處,歡迎指正!
一、簡書 - JDK1.8紅黑樹實現分析
二、知乎 - 史上最清晰的紅黑樹講解
做者:炸雞可樂
出處:www.pzblog.cn