STL-红黑树源码实现
紅黑樹的介紹
它是一種特殊的二叉查找樹,紅黑樹的每個節點上都有存儲位表示節點的顏色,可以是紅或者黑。
紅黑樹的特性
1.每個節點或者黑色或者紅色
2.根節點是黑色
3.每個葉子節點是黑色
4.如果一個節點是紅色,它的子節點必須是黑色的
5.從一個節點到該節點的子孫節點的所有路徑上包含相同數目的黑節點
紅黑樹的操作
左旋
對x進行左旋,意味著“將X變為一個左節點”
右旋
平衡調節
新插入X,父節點P,G是P的父節點,S是G的另外一個子節點。
新節點x必須為葉節點,插入的節點必須為紅色;
如果P是紅色,必須調整紅色,根據X的插入位置,有4種情況:
1:S為黑色且X為外側插入,先對P,G左一次單旋轉,在更改P,G顏色,重新滿足紅黑樹的規則3:
2.S為黑且X為內側插入,先對P,X做一次單旋轉并更改G,X顏色,再將結果對G做一次單旋轉,滿足紅黑樹的規則
3.S為紅色,且X為外側插入,先對P和G做一次單旋轉,并改變X的顏色,此時,如果GG(G的父節點)為黑色,符合規則;否則,進入情況4
?
或者
4.S為紅色且X為外側插入,先對P和G做一次單旋轉,并改變X的顏色,如果G的父節點,仍然為紅色,繼續往上做,直到父子連續部位紅的情況。
或者
?
紅黑樹的實現
節點的定義
struct _Node {
?? ??? ?_Nodeptr _Left, _Parent, _Right;
?? ??? ?_Ty _Value;
?? ??? ?_Redbl _color;
?? ?};
節點的父節點,左右孩子節點
?
初始化
申請一個節點,賦值給_Nil, 并且左右子節點為0;并在構造一個節點_Head,并且設置為紅色節點,父指針指向_Nil節點,左右子節點都指向自己。
_Head節點和紅黑樹的根節點的父節點,是相互指向。
_Nil用來表示null節點。
_Lmost,指向最左邊的節點,_Rmost,指向最右邊的節點,可以用來求最小和最大值。
void _Init() {
?? ??? ?_Nodeptr _Tmp = _Buynode(0, _Black);
?? ??? ?{
?? ??? ??? ?_Lockit _Lk;
?? ??? ??? ?if (_Nil == 0) {
?? ??? ??? ??? ?_Nil = _Tmp;
?? ??? ??? ??? ?_Tmp = 0;
?? ??? ??? ??? ?_Left(_Nil) = 0, _Right(_Nil) = 0;
?? ??? ??? ?}
?? ??? ??? ?++_Nilerefs;
?? ??? ?}
?? ??? ?if (_Tmp != 0) {
?? ??? ??? ?_Freenode(_Tmp);
?? ??? ?}
?? ??? ?_Head = _Buy(_Nil, _Red), _Size = 0;
?? ??? ?_Lmost() = _Head, _Rmost() = _Head;
?? ?}
數據的插入
實現左旋
_Nodeptr _Y = _Right(_X);
?? ??? ?_Right(_X) = _Left(_Y);
?? ??? ?if (_Left(_Y) != _Nil) {
?? ??? ??? ?_Parent(_Left(_Y)) = _X;
?? ??? ?}
?? ??? ?_Parent(_Y) = _Parent(_X);
?? ??? ?if (_X == _Root()) {
?? ??? ??? ?_Root() = _Y;
?? ??? ?}
?? ??? ?else if (_X == _Left(_Parent(_X))) {
?? ??? ??? ?_Left(_Parent(_X)) = _Y;
?? ??? ?}
?? ??? ?else {
?? ??? ??? ?_Right(_Parent(_X)) = _Y;
?? ??? ?}
?? ??? ?_Left(_Y) = _X;
?? ??? ?_Parent(_X) = _Y;
?? ?}
實現右旋
void _Rrotate(_Nodeptr _X) {
?? ??? ?_Nodeptr _Y = _Left(_X);
?? ??? ?_Left(_X) = _Right(_Y);
?? ??? ?if (_Right(_Y) != _Nil) {
?? ??? ??? ?_Parent(_Right(_Y)) = _X;
?? ??? ?}
?? ??? ?_Parent(_Y) = _Parent(_X);
?? ??? ?if (_X == _Root())
?? ??? ??? ?_Root() = _Y;
?? ??? ?else if (_X == _Right(_Parent(_X))) {
?? ??? ??? ?_Right(_Parent(_X)) = _Y;
?? ??? ?}
?? ??? ?else {
?? ??? ??? ?_Left(_Parent(_X)) = _Y;
?? ??? ?}
?? ??? ?_Right(_Y) = _X;
?? ??? ?_Parent(_X) = _Y;
?? ?}
紅黑樹刪除
紅黑樹的刪除分為兩種情況,情況1是有兩個子的情況,情況2最多有一個子樹的情況
?_Nodeptr _X;
?? ??? ?_Nodeptr _Y = (_P++)._Mynode();
?? ??? ?_Nodeptr _Z = _Y;
_Y:表示的是要刪除的節點,_P表示的是臨近_Y的大的節點
_Z:賦值為_Y
情況1:最多有一個子樹的情況
- ? ?如果左子樹或者右子樹為空的情況? ?
if (_Left(_Y) == _Nil) {
?? ??? ??? ?_X = _Right(_Y);
?? ??? ?}
?? ??? ?else if (_Right(_Y) == _Nil) {
?? ??? ??? ?_X = _Left(_Y);
?? ??? ?}
?
把_X分別設置為右子樹和左子樹。
- 然后把_X的父節點,設置為_Y的父節點即可;
? ? ? _Parent(_X) = _Parent(_Y);
- 特殊情況判斷,如果為root()節點
if (_Root() == _Z)
?? ??? ??? ??? ?_Root() = _X;
否則就設置_Z的左右子樹
else if (_Left(_Parent(_Z)) == _Z) {
?? ??? ??? ??? ?_Left(_Parent(_Z)) = _X;
?? ??? ??? ?}
?? ??? ??? ?else {
?? ??? ??? ??? ?_Right(_Parent(_Z)) = _X;
?? ??? ??? ?}
- 判斷是否為_Lmost??
if (_Lmost() != _Z) {
?? ??? ??? ??? ?;
?? ??? ??? ?}
如果_Z是_Lmost就把_Z的父節點,設置為_Lmost
?? ??? ??? ?else if (_Right(_Z) == _Nil) {
?? ??? ??? ??? ?_Lmost() = _Parent(_Z);
?? ??? ??? ?}
?? ??? ??? ?else {
?? ??? ??? ??? ?_Lmost() = _Min(_X);
?? ??? ??? ?}
_Rmost的判斷是同樣的。
情況2:有兩個子樹的情況
?? ??? ??? ?_Y = _Min(_Right(_Y));
?? ??? ??? ?_X = _Right(_Y);
去_Y的右子樹的最小節點,然后把_X置為該節點的右數,_Z是要刪除的節點。目的是把_Y這個節點,放到_Z的位置上去;接下來就是要調整,_Z,_Y的左右子樹和父節點的指向。
- 更新_Z的左右子樹的父節點的指向為_Y
_Parent(_Left(_Z)) = _Y;
- 更新_Y的左子樹的指向為_Z的左子樹的指向
?_Left(_Y) = _Left(_Z);
- 如果恰好_Y==_Right(_Z)
if (_Y == _Right(_Z)) {
?? ??? ??? ??? ?_Parent(_X) = _Y;
?? ??? ??? ?}
- 否則
? ? ? ? ? ? ? ? ? ? _Parent(_X) = _Parent(_Y);
?? ??? ??? ??? ??? ?_Left(_Parent(_Y)) = _X;
?? ??? ??? ??? ??? ?_Right(_Y) = _Right(_Z);
?? ??? ??? ??? ??? ?_Parent(_Right(_Z)) = _Y;
刪除后平衡調整
如果刪除的是黑色節點,才需要進行平衡調整。
分析左子樹的情況:
while (_X != _Root() && _Color(_X) == _Black) {
?? ??? ??? ??? ?if (_X == _Left(_Parent(_X))) {
- 獲取_X節點的父節點的右子樹
_Nodeptr _W = _Right(_Parent(_X));
- 如果_W的顏色是紅色
_Color(_W) = _Black;
?? ??? ??? ??? ??? ??? ?_Color(_Parent(_X)) = _Red;
?? ??? ??? ??? ??? ??? ?_Lrotate(_Parent(_X));
?? ??? ??? ??? ??? ??? ?_W = _Right(_Parent(_X));
if (_Color(_Left(_W)) == _Black&&_Color(_Right(_W)==_Black) {
?? ??? ??? ??? ??? ??? ?_Color(_W)=_Red;
?? ??? ??? ??? ??? ??? ?_X=_Parent(_X);
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?else {
?? ??? ??? ??? ??? ??? ?if (_Color(_Right(_W)) == _Black) {
?? ??? ??? ??? ??? ??? ??? ?_Color(_Left(_W))=_Black;
?? ??? ??? ??? ??? ??? ??? ?_Color(_W)=_Red;
?? ??? ??? ??? ??? ??? ??? ?_Rrotate(_W);
?? ??? ??? ??? ??? ??? ??? ?_W=_Right(_Parent(_X));
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ?_Color(_W) = _Color(_Parent(_X));
?? ??? ??? ??? ??? ??? ?_Color(_Parent(_X)) = _Black;
?? ??? ??? ??? ??? ??? ?_Color(_Right(_W)) = _Black;
?? ??? ??? ??? ??? ??? ?_Lrotate(_Parent(_X));
?? ??? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ??? ?}
總結
以上是生活随笔為你收集整理的STL-红黑树源码实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: x265-common.h
- 下一篇: STL-String源码分析