紅黑樹動圖解析
一、啥是紅黑樹?
紅黑樹(Red Black Tree) 是一種自平衡二叉查找樹,是在計算機科學中用到的一種數據結構,典型的用途是實現關聯數組。因此想要弄清楚紅黑樹,我們需要先解決幾個問題:
- 二叉查找樹是什麼?
- 爲什麼會出現紅黑樹?
二、剖析二叉查找樹
二叉查找樹特性
二叉查找樹(Binary Search Tree)是一顆二叉樹,簡稱BST。就像我們說int都是整數一樣,BST這一種二叉樹需要滿足如下三個特性:
- 某節點的左子樹節點值僅包含小於該節點值
- 某節點的右子樹節點值僅包含大於該節點值
- 左右子樹每個也必須是二叉查找樹
長啥樣?
在線演示BST網址:https://www.cs.usfca.edu/~galles/visualization/BST.html
ps:這個網站不只二叉樹,絕大部分算法的增刪改查都可以去演示,是理解算法的好幫手,強烈建議保存!
BST在理想情況下是如下這樣的:
當BST發生傾斜後是這樣的:
在理想的情況下,二叉查找樹增刪查改的時間複雜度爲O(logN)(其中N爲節點數),最壞的情況下爲O(N)。
怎麼解決傾斜
通過以上兩個相同數據的BST的演示,我們發現了一個問題,同樣的數據組成,只是因爲數據插入的先後順序,就使得產生的二叉查找樹發生了傾斜。
那麼我們怎麼解決這個問題呢?首先想到的就是每次插入或者刪除數據的時候都進行判斷,對已經存在的樹結構進行旋轉,使其維持在logN的高度上,這樣不管我們按照什麼樣的順序插入數據,最終的結構只要能滿足logN的高度,那它的結構一定是理想狀態下的。
紅黑樹產生
基於BST存在的問題,一種新的樹——平衡二叉查找樹(Balanced BST)產生了。平衡樹在插入和刪除的時候,會通過旋轉操作將高度保持在logN。其中兩款具有代表性的平衡樹分別爲AVL樹和紅黑樹。AVL樹由於實現比較複雜,而且插入和刪除性能差,因此在實際環境中我們更多的是應用紅黑樹。
三、紅黑樹的用途及特性
用途
紅黑樹(Red-Black Tree)以下簡稱RBTree的實際應用非常廣泛,比如Linux內核中的完全公平調度器、高精度計時器、ext3文件系統等等,各種語言的函數庫如Java的TreeMap和TreeSet,C++ STL的map、multimap、multiset等,是函數式語言中最常用的持久數據結構之一。
由於在java8裏HashMap的底層實現用RBTree取代鏈表,使得性能得到了提升,因此很多人才去關注或者深入學習紅黑樹。
特性
RBT樹上的每個節點,都要遵循下面的規則:
- 每個節點都是紅色或者黑色;
- 根節點必須始終是黑色;
- 沒有兩個相鄰的紅色節點;
- 對每個結點,從該結點到其子孫節點的所有路徑上包含相同數目的黑結點。
RBT樹在理論上還是一棵BST樹,但是它在對BST的插入和刪除操作時會維持樹的平衡,即保證樹的高度在[logN,logN+1](理論上,極端的情況下可以出現RBTree的高度達到2*logN,但實際上很難遇到)。這樣RBTree的查找時間複雜度始終保持在O(logN)從而接近於理想的BST。RBTree的刪除和插入操作的時間複雜度也是O(logN)。RBT的查找操作就是BST的查找操作。
上面的規則看一下有個印象就好,接下來是紅黑樹比較複雜的地方,就是紅黑樹的調整,
爲了達到這一目的,
四、拒絕死記硬背,跟着動圖理解調整算法
爲了維持RBT的規則,RBT定義了兩個重要的操作:
- rotation:旋轉,這是樹達到平衡的關鍵;
- recolor :重新標記黑色或紅色。
4.1、 首先先看最基礎的recolor,也就是第一種情況
先看如下gif:
小結一波:
通過上面動圖,我們發現整個插入及調整一共是如下7步:
- 新插入的節點004標記爲紅色;
- 插入後發現004的父節點005也是紅色,違反了RBT的規則3( 沒有兩個相鄰的紅色節點);
- 發現004的叔父節點007同樣是紅色;
- 使用recolor方法,把005和007也就是父節點和叔父節點標記爲黑色;
- 將004和它的祖父節點006標記爲相同的顏色,也就是紅色,往上遞歸重複步驟2,3;
- 發現它的祖父節點是根節點,標記爲黑色;
- 調整完畢。
4.2、開始考慮旋轉rotation方法,首先展示第二種情況:左旋
先看如下gif:
小結一波:
這裏我們就不用再分步驟去看了,只需要知道整體的調整方式就行了;左旋就是當新加入節點之後,樹的高度及顏色不再滿足RBT定義的規則後;將不滿足的節點進行左旋轉,使得它取代之前它的父節點,同時它的父節點變爲它的左子節點,最後應用第一種方法調整顏色的過程。
4.3、第三種情況:右旋
先看如下gif:
小結一波:
右旋就是以某節點爲中心進行向右的旋轉,取代併成爲之前自己的父節點,然後把之前的父節點變爲自己的右子節點,最後應用第一種方法調整顏色的過程。
五、總結
最後我們把實際使用中,或者研究HashMap源碼時需要提前瞭解的紅黑樹調整規則整理總結一下:
爲了方便記憶,我們取英文首字母,定義連續的三代節點,新增節點爲N,父節點爲P,叔父節點爲U,祖父節點爲G
情況 | 處理方式 |
---|---|
N和U都是紅色 | 將P和U修改爲黑色,G修改爲紅色 |
N是P的左節點,同時U是黑色 | 對G進行一次右旋轉,然後根據規則調整顏色 |
N是P的右節點,同時U是黑色 | 首先對P進行一次左旋轉,然後套用上一種調整情況 |
紅黑樹看似複雜,其實只要我們理解了它的來源,定義的規則,爲了完成規則使用的方法及三種調整策略,然後多加練習,多觀察,就可以很容易的去掌握它的規律。