紅黑樹
,非常經典的數據結構,主要用於一些容器中,比如C++
語言中的map
、Java
語言中的TreeMap
(後面會寫源碼分析博客)。紅黑樹
能保持高效的查找,一般取時間複雜度爲O(log2n),由於高效,這個結構也比較複雜,所以很多人(包括我自己)都一直搞不懂紅黑樹
到底是怎麼插入
、刪除
節點的。此篇博客,博主將圖文並茂的一層一層揭開紅黑樹
神祕面紗。
要徹底搞懂紅黑樹
,難度還是比較大的,建議先閱讀我之前寫的兩篇博客做鋪墊,數據結構之二叉樹、AVL樹、紅黑樹、Trie樹、B樹、B+樹、B*樹淺析、數據結構之二叉搜索樹詳解(附C++代碼實現查找、插入、刪除操作)。前者是通識篇,主要介紹了幾種樹結構的區別,後者單獨介紹二叉搜索樹
插入、刪除操作。(其實紅黑樹
= 二叉搜索樹
+ 弱平衡
)
數據結構之紅黑樹
一、紅黑樹
概述
1、什麼是紅黑樹
?
紅黑樹
是一棵二叉搜索樹
,並且這棵樹實現了弱平衡
(嚴格的平衡是對於樹中任意節點的左右子樹高度差不超過1)。弱平衡
是指任意節點到到其子樹中的葉節點
所經過的黑色節點
數相同,也可以稱爲黑色平衡
(因爲嚴格平衡的二叉搜索樹AVL,維護成本太高,所以退而求其次)。
2、紅黑樹
的五大特性
紅黑樹
的五大特性:
1、節點是紅色或者是黑色
2、根節點是黑色
3、每個葉節點(NIL或空節點)是黑色
4、每個紅色節點的兩個子節點都是黑色的
5、任意節點到其子樹中的葉節點所經過的黑色節點數相同(黑高相同)
紅黑樹
引入了NIL
節點,用於填充節點的左或右爲空的位置,因此紅黑樹
中的葉節點
特指NIL
節點。
一說定義,博客的畫風瞬間變得枯燥起來了,可能有些小夥伴已經開始有牴觸情緒的。這些特徵你可以不用記住,後面用到的時候我會反覆提出來的。
3、爲什麼要引入紅黑樹
還記不記得在博客 數據結構之二叉搜索樹詳解(附C++代碼實現查找、插入、刪除操作) 中使用二叉搜索樹遇到的插入有序遞增序列退化成鏈表的缺陷。
如果不引入平衡
的概念,這種普通的二叉搜索樹的效率將大大降低。但是引入強平衡
(樹中任意節點的左右子樹高度差不超過1),形如AVL
樹,樹的維護成本太高。爲此Rudolf Bayer
發明了一種帶顏色標記的二叉搜索樹即紅黑樹
,此樹弱平衡
,任意節點到其子樹中的葉節點所經過的黑色節點數相同。
二、紅黑樹
相關操作
紅黑樹
看起來挺簡單的,不就是給每個節點都表上顏色麼。但是實際維護還是比較複雜的,比如刪除了一個節點如何調整?新增了一個節點表什麼顏色?插入後樹要進行怎樣的調整?
1、節點旋轉
爲了調整紅黑樹
的平衡,引入了兩種旋轉操作。具體過程請看圖。
①、左旋
左旋
,將旋轉節點B
放到它的父節點A
的位置,將父節點A
置爲旋轉節點B
的左子樹,然後將旋轉節點B
的左子樹放到父節點A
的右子節點位置。
②、右旋
右旋
,將旋轉節點B
放到它的父節點A
的位置,將父節點A
置爲旋轉節點B
的右子樹,然後將旋轉節點B
的右子樹放到父節點A
的左子節點位置。
2、查找節點
查找節點
是紅黑樹
三大操作中最爲簡單的操作,因爲紅黑樹
是一棵特殊的二叉搜索樹
,所以按照二叉搜索樹
的查找方式查找即可。查找僞代碼:
root 紅黑樹根,target 需要查找的value
while root != NULL
if root->value == target
// 查找成功
break
else if root->value > target
// 二叉搜索樹 左子樹任意節點.value < 根.value < 右子樹任意節點.value
// 根.value > target,則target只可能存在左子樹中
root = root->left
else
// 二叉搜索樹 左子樹任意節點.value < 根.value < 右子樹任意節點.value
// 根.value < target,則target只可能存在右子樹中
root = root->right
// root == NULL,則說明未找到
return root
紅黑樹
中元素查找示例圖解:
3、插入節點
紅黑樹
中插入節點是稍微複雜一點點的操作,請保證前面的都消化完畢再繼續閱讀。