前言
11.1新的一月加油!這個購物狂歡的季節,一看,已囊中羞澀!趕緊來惡補一下紅黑樹和2-3樹吧!紅黑樹真的算是大名鼎鼎了吧?即使你不了解它,但一定聽過吧?下面跟隨我來揭開神秘的面紗吧!
一、2-3樹
1、搶了紅黑樹的光環?
今天的主角是紅黑樹,是無疑的,主角光環在呢!那2-3樹又是什么鬼呢?學習2-3樹不僅對理解紅黑樹有幫助,對理解B類樹,也是有巨大幫助的,所以學習2-3樹很必要!
2、基本性質
2-3樹滿足二分搜索樹的基本性質,但節點可以存放一個元素或兩個元素!如下圖,就是2-3樹:

說明:2-3樹一顆絕對平衡的樹(絕對平衡:對於任意一個節點,左右子樹高度相同)
3、維護絕對平衡
2-3樹在插入過程中如何維護絕對平衡呢?進行畫圖演示,實在有點不好畫,如下圖:

說明:
1、不能將新節點插入到空節點
因為那樣如上圖,就不滿足絕對平衡了,所以可以將37和42合並,2-3支持3節點。
2、不支持4節點,進行拆分
再插入12時,也不能插入空節點,也要合並,但2-3樹不支持4節點,所以進行進行拆分。
3、子節點達到3節點,合並到父節點
再依次插入18、6,達到4節點,進行拆分,但不符合絕對平衡了怎么辦?將12和37合並,就形成了最后3節點的圖了
總結:講到這里,應該對2-3樹如何維護絕對平衡,應該了解了吧?理解2-3樹,對於再理解紅黑樹,是非常有幫助的,其實,它們有等價性的,接下來會說明的。
二、紅黑樹
1、紅黑樹和2-3樹的等價性
也想達到像2-3樹那樣的絕對平衡,但2-3樹的實現比較麻煩,所以產生了紅黑樹;那么,紅黑樹和2-3樹有怎么樣的等價性呢?如下圖:

說明:紅黑樹最開始想用紅線區別b、c,但實現起來比較困難,然后用紅黑來表示節點,就比較好實現了!
紅黑樹和2-3樹總體對比圖,可以參考一下:

2、紅黑樹5個重要性質
1、引自《算法導論》
紅黑樹有五個重要性質,引自算法界一本聖潔《算法導論》中的內容,如下:

是不是看着有點暈,下面我進行解釋。
2、5個重要性質
1、每一個節點或者紅色的,或是黑色的
2、根節點是黑色的
3、每一個葉子節點(最后的空節點)是黑色的
4、如果一個節點是紅色的,那么它的孩子節點都是黑色的
5、從任意節點到葉子節點,經過的黑色節點是一樣的
解釋:最重要的性質是第五條,前4條在理解2-3樹之后,就很好理解了,第5條性質說明了:紅黑樹是保持“黑平衡”的二叉樹;
嚴格意義上來說,紅黑樹不是平衡二叉樹,最大高度:2logn,但是時間復雜度仍然是O(logn),因為2是常數,但比AVL樹查詢要稍微慢一些。
三、紅黑樹添加元素
紅黑樹添加元素,比較繁瑣,因為要保持上面的五個性質,要不然就不是紅黑樹了;
1、保持根節點為節點
紅黑樹的節點類也可以從二分搜索樹上進行修改,但要新增“color”成員變量,來標注節點顏色,節點類如下:
template<typename Key, typename Value>
class RBTree {
private:
static const bool RED = true;
static const bool BLACK = false;
struct Node {
Key key;
Value value;
Node *left;
Node *right;
bool color;
Node(Key key, Value value) {
this->key = key;
this->value = value;
this->left = this->right = nullptr;
color = RED; //默認初始化為紅色
}
Node(Node *node) {
this->key = node->key;
this->value = node->value;
this->left = node->left;
this->right = node->right;
this->color = node->color;
}
};
Node *root;
int size;
}
因為紅黑樹性質1要求根節點為黑色,所以要保持根節點為黑色;
2、左旋轉
像AVL樹一樣,紅黑樹也需要左旋和右旋,如下圖就需要左旋轉,因為“紅色節點是左傾斜的”:

說明:圖中黑色字體標識黑色節點,紅色表示紅色節點,並演示了旋轉過程,最后還要改變節點顏色。
3、左旋轉代碼實現
代碼如下:
Node *leftRotate(Node *node) {
Node *x = node->right;
node->right = x->left;
x->left = node;
x->color = node->color;
node->color = RED;
return x;
}
4、顏色反轉
下面這種情況就需要顏色反轉,如下圖:

5、顏色反轉代碼實現
代碼如下:
void flipColors(Node *node) {
node->color = RED;
node->left->color = BLACK;
node->right->color = BLACK;
}
6、右旋轉
下面情況需要右旋轉,如下圖:

旋轉之后,如下圖:

7、右旋轉代碼如下
代碼如下:
Node *rightRotate(Node *node) {
Node *x = node->left;
node->left = x->right;
x->right = node;
x->color = node->color;
node->color = RED;
return x;
}
8、總體流程圖

9、總體代碼
總體代碼如下,供參考和學習:
View Code
總結
面試時99.9%不會讓手寫一下紅黑樹的添加過程,除非你面試算法工程師,那就打擾了!主要理解紅黑樹的性質、左旋和右旋等。
歡迎點贊和評論,感謝支持!

