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