亚洲国产日韩人妖另类,久久只有这里有精品热久久,依依成人精品视频在线观看,免费国产午夜视频在线

      
      

        最透徹的紅黑樹詳解(圖文并茂,一文全解)

        最透徹的紅黑樹詳解(圖文并茂,一文全解)

        前言

        ??剛開始接觸紅黑樹的時(shí)候,感覺很難。其實(shí)不然,紅黑樹只是情況分的多了一點(diǎn)而已,相較于線段樹,主席樹等等,簡(jiǎn)單多了。對(duì)于紅黑樹3種插入維護(hù)4種刪除維護(hù)沒必要去記憶,稍作了解,對(duì)于紅黑樹的性質(zhì)和特點(diǎn),需要特別記憶。

        ??本專欄知識(shí)點(diǎn)是通過零聲教育的線上課學(xué)習(xí),進(jìn)行梳理總結(jié)寫下文章,對(duì)c/c++linux課程感興趣的讀者,可以點(diǎn)擊鏈接:C/C++Linux服務(wù)器開發(fā)/后臺(tái)架構(gòu)師【零聲教育】-學(xué)習(xí)視頻教程-騰訊課堂課程介紹詳細(xì)查看課程的服務(wù)。

        注意,本文圖中紅黑樹的葉子結(jié)點(diǎn)默認(rèn)不畫出來~

        為什么要有紅黑樹

        二叉搜索樹

        ??二叉搜索樹(又叫二叉排序樹,BST):對(duì)于任意一個(gè)結(jié)點(diǎn),其左子樹的值必定小于該結(jié)點(diǎn),其右子樹的值必定大于該結(jié)點(diǎn)。那么中序遍歷的時(shí)候,就是有序的了。理論上來說,增加,刪除,修改的時(shí)間復(fù)雜度都是O(log(N))。但是它存在一個(gè)致命的問題。

        ??退化:向樹中插入[1,2,3,4,5,6],此時(shí)樹退化成了一個(gè)鏈表,增加,刪除,修改的時(shí)間復(fù)雜度退化為O(N)

        添加圖片注釋,不超過 140 字(可選)

        平衡二叉搜索樹

        ??平衡二叉搜索樹(AVL Tree):它的左右兩個(gè)子樹的高度差的絕對(duì)值不超過1,并且左右兩個(gè)子樹都是一棵平衡二叉搜索樹。如果向樹中插入[1,2,3,4,5,6]

        添加圖片注釋,不超過 140 字(可選)

        可以看到AVLTree在最壞的情況下,依然保持了“絕對(duì)的平衡”:左右兩個(gè)子樹的高度差的絕對(duì)值不超過1。那么AVL Tree是如何保證平衡的呢,是通過旋轉(zhuǎn),可以看到,無論是插入還是刪除元素,都要去通過旋轉(zhuǎn)維護(hù)整個(gè)樹的平衡。

        • AVL查詢?cè)兀篛(log(N))
        • AVL插入元素:最多一次旋轉(zhuǎn)O(1),加上查詢的時(shí)間O(log(N)),插入的復(fù)雜度O(log(N))
        • AVL刪除元素:必須檢查從刪除結(jié)點(diǎn)開始到根結(jié)點(diǎn)路徑上的所有結(jié)點(diǎn)的平衡因子。因此刪除的代價(jià)比較大,刪除最多需要log(N)次旋轉(zhuǎn),加上查詢的時(shí)間,刪除的復(fù)雜度O(2log(N))

        紅黑樹

        ??我們發(fā)現(xiàn),AVL樹未免太嚴(yán)格了一些,有沒有一種數(shù)據(jù)結(jié)構(gòu),能讓AVL樹不那么嚴(yán)格平衡,降低維護(hù)平衡的開銷,同時(shí)又不能像BST一樣退化呢?

        當(dāng)然有,就是本文所寫的紅黑樹(rbTree):

        • rbTree查詢?cè)兀篛(log(N))
        • rbTree插入元素:插入最多2次旋轉(zhuǎn),加上查詢的時(shí)間O(log(N)),插入的復(fù)雜度O(log(N))
        • rbTree刪除元素:刪除最多需要3次旋轉(zhuǎn),加上查詢的時(shí)間,刪除的復(fù)雜度O(log(N))

        ??雖然插入和刪除元素后,需要旋轉(zhuǎn)和變色(本文中統(tǒng)一為維護(hù)),但是這一時(shí)間復(fù)雜度可以估算為O(1)不計(jì)

        ??因?yàn)閞bTree的第6條性質(zhì)(見下文)

        • 所以紅黑樹的查詢效率略低與AVL的查詢
        • 紅黑樹和AVL插入的速度差不多
        • 紅黑樹刪除的速度比AVL快,因?yàn)锳VL刪除最多需要og(N)次旋轉(zhuǎn)

        紅黑樹的應(yīng)用場(chǎng)景

      1. c++ stl map,set(紅黑樹的封裝)
      2. 進(jìn)程調(diào)度cfs(用紅黑樹存儲(chǔ)進(jìn)程的集合,把調(diào)度的時(shí)間作為key,那么樹的左下角時(shí)間就是最小的)
      3. 內(nèi)存管理(每次使用malloc的時(shí)候都會(huì)分配一塊小內(nèi)存出來,那么這么塊就是用紅黑樹來存,如何表述一段內(nèi)存塊呢,用開始地址+長(zhǎng)度來表示,所以key->開始地址,val->大?。?/li>
      4. epoll中使用紅黑樹管理socketfd
      5. nginx中使用紅黑樹管理定時(shí)器,中序遍歷第一個(gè)就是最小的定時(shí)器
      6. 紅黑樹的性質(zhì)(重點(diǎn))

      7. 每個(gè)結(jié)點(diǎn)是紅的或者黑的
      8. 根結(jié)點(diǎn)是黑的
      9. 每個(gè)葉子結(jié)點(diǎn)是黑的(因?yàn)檫@條性質(zhì),一般用葉子結(jié)點(diǎn)在代碼中被特殊表示)
      10. 如果一個(gè)結(jié)點(diǎn)是紅的,則它的兩個(gè)兒子都是黑的(不存在相鄰紅色
      11. 從任一節(jié)點(diǎn)到葉子節(jié)點(diǎn),所包含的黑色節(jié)點(diǎn)數(shù)目相同(即黑高度相同)
      12. 最長(zhǎng)路徑長(zhǎng)度不超過最短路徑長(zhǎng)度的2倍(2n-1,一條黑紅黑紅…一條全黑)
      13. 紅黑樹的定義

        #define RED 0#define BlACK 1typedef int KEY_TYPE;typedef struct _rbtree_node { unsigned char color;//顏色 struct _rbtree_node *left;//左子樹 struct _rbtree_node *right;//右子樹 struct _rbtree_node *parent;//父結(jié)點(diǎn) KEY_TYPE key; void *value;} rbtree_node;//紅黑樹結(jié)點(diǎn)typedef struct _rbtree { rbtree_node *root;//根結(jié)點(diǎn) rbtree_node *nil;//通用葉子結(jié)點(diǎn)} rbtree;//紅黑樹

        紅黑樹的左旋與右旋

        動(dòng)三個(gè)方向,改6個(gè)指針。 通過旋轉(zhuǎn),調(diào)整左右高度,使樹達(dá)到平衡。

        添加圖片注釋,不超過 140 字(可選)

        左旋leftRotate(T,x)—中右->左中

        降低X結(jié)點(diǎn)的高度,提高X結(jié)點(diǎn)右結(jié)點(diǎn)(即Y)的高度。

      14. x的右子樹指向y的左子樹
      15. 本來指向x結(jié)點(diǎn)的父指針,改成指向y
      16. y的左子樹指向x結(jié)點(diǎn)
      17. 添加圖片注釋,不超過 140 字(可選)

        右旋rightRotate(T,y)—中左->中右

        降低Y結(jié)點(diǎn)的高度,提高Y結(jié)點(diǎn)左結(jié)點(diǎn)(即X)的高度。

      18. y的左子樹指向x的右子樹
      19. 本來指向y結(jié)點(diǎn)的父指針,改成指向x
      20. x的右子樹指向y結(jié)點(diǎn)
      21. 添加圖片注釋,不超過 140 字(可選)

        //左旋leftRotate(T,x)—中右->左中//降低X結(jié)點(diǎn)的高度,提高X結(jié)點(diǎn)右結(jié)點(diǎn)(即Y)的高度。void _left_rotate(rbtree *T, rbtree_node *x) { rbtree_node *y = x->right; //1 x->right = y->left;//x的右子樹指向y的左子樹 if (y->left != T->nil) { y->left->parent = x;//y的左子樹的父節(jié)點(diǎn)指向x } //2 y->parent = x->parent;//y的父結(jié)點(diǎn)指向x的父結(jié)點(diǎn) if (x->parent == T->nil) {//如果x是根結(jié)點(diǎn) T->root = y; } else if (x == x->parent->left) { x->parent->left = y;//本來指向x結(jié)點(diǎn)的父指針,改成指向y } else { x->parent->right = y; } //3 y->left = x;//y的左子樹指向x結(jié)點(diǎn) x->parent = y;//x的父節(jié)點(diǎn)指向y}//右旋//copy左旋的代碼//left改成right,right改成left//x改成y,y改成xvoid _right_rotate(rbtree *T, rbtree_node *y) { rbtree_node *x = y->left; //1 y->left = x->right; if (x->right != T->nil) { x->right->parent = y; } //2 x->parent = y->parent; if (y->parent == T->nil) { T->root = x; } else if (y == y->parent->right) { y->parent->right = x; } else { y->parent->left = x; } //3 x->right = y; y->parent = x;}

        紅黑樹插入結(jié)點(diǎn)與插入維護(hù)紅黑樹的三種情況

        插入結(jié)點(diǎn)

        ??在插入結(jié)點(diǎn)時(shí),我們始終認(rèn)為“插入這個(gè)結(jié)點(diǎn)之前,原來的紅黑樹是滿足紅黑樹性質(zhì)的==”,那么插入的位置容易找,就是不斷的對(duì)比key,最終找到位置,那么新增的結(jié)點(diǎn)是什么顏色呢?我們通過性質(zhì)發(fā)現(xiàn):

        • 如果新結(jié)點(diǎn)是黑色,違背了第5條性質(zhì)
        • 如果新結(jié)點(diǎn)是紅色,可能違背第4條性質(zhì)

        而第四條性質(zhì),我們可以通過旋轉(zhuǎn)與上色的方式修復(fù),所以在我們插入結(jié)點(diǎn)的時(shí)候,我們始終認(rèn)為新結(jié)點(diǎn)是紅色

        //因?yàn)閭魅氲膋ey可能是字符,可能是整形,所以要提取出來//這里可以看出,其實(shí)可以封裝成一個(gè)模板int key_compare(KEY_TYPE a, KEY_TYPE b) { //這里假設(shè)是int if (a > b) { return 1; } else if (a root; rbtree_node *y = T->nil;//y是x的父節(jié)點(diǎn) while (x != T->nil) {//二分找位置 y = x; if (key_compare(z->key, x->key) left; } else if (key_compare(z->key, x->key) > 0) { x = x->right; } else { //如果key相等,看自己的業(yè)務(wù)情景 //重復(fù)插入可以不修改直接退出,可以修改val return; } } //插入 z->parent = y; if (y == T->nil) { T->root = z; } else if (key_compare(z->key, y->key) left = z; } else { y->right = z; } z->left = T->nil; z->right = T->nil; z->color = RED; //維護(hù)紅黑樹 rbtree_insert_fixup(T, z);}

        插入結(jié)點(diǎn)后維護(hù)紅黑樹

        ??我們知道新增結(jié)點(diǎn)是紅色,如果新結(jié)點(diǎn)是父節(jié)點(diǎn)也是紅色,那么就需要維護(hù)紅黑樹了。

        ??如果父結(jié)點(diǎn)是爺結(jié)點(diǎn)是左子樹,可以歸納出來三種情況。同理如果父結(jié)點(diǎn)是爺結(jié)點(diǎn)是右子樹,我們也可以歸納出來三種情況。但是這三種情況的差異就是旋轉(zhuǎn)方向的區(qū)別而已。一共是6種情況,但是歸納出來其實(shí)是3種,讀者不要搞錯(cuò)了。

        在下面的圖中:z表示新增結(jié)點(diǎn),y表示叔結(jié)點(diǎn)

        父結(jié)點(diǎn)是爺結(jié)點(diǎn)是左子樹

        1. 叔結(jié)點(diǎn)是紅色的

        • 將叔結(jié)點(diǎn)和父結(jié)點(diǎn)變黑,爺結(jié)點(diǎn)變紅
        • 將當(dāng)前結(jié)點(diǎn)變成爺結(jié)點(diǎn)(因?yàn)闋斀Y(jié)點(diǎn)是紅,爺結(jié)點(diǎn)的父節(jié)點(diǎn)也可能是紅,所以要遞歸維護(hù))

        添加圖片注釋,不超過 140 字(可選)

        2. 叔結(jié)點(diǎn)是黑色的且新結(jié)點(diǎn)是左子樹

        • 將父結(jié)點(diǎn)變成黑色,爺結(jié)點(diǎn)變成紅色
        • 以爺結(jié)點(diǎn)為中心右旋

        添加圖片注釋,不超過 140 字(可選)

        3. 叔結(jié)點(diǎn)是黑色的且新結(jié)點(diǎn)是右子樹

        • 以父結(jié)點(diǎn)為中心左旋
        • 將父結(jié)點(diǎn)變黑色,爺結(jié)點(diǎn)變紅色
        • 以爺結(jié)點(diǎn)為中心右旋

        添加圖片注釋,不超過 140 字(可選)

        父結(jié)點(diǎn)是爺結(jié)點(diǎn)是右子樹

        1. 叔結(jié)點(diǎn)是紅色的

        • 將叔結(jié)點(diǎn)和父結(jié)點(diǎn)變黑,爺結(jié)點(diǎn)變紅
        • 將當(dāng)前結(jié)點(diǎn)變成爺結(jié)點(diǎn)(因?yàn)闋斀Y(jié)點(diǎn)是紅,爺結(jié)點(diǎn)的父節(jié)點(diǎn)也可能是紅,所以要遞歸維護(hù))

        添加圖片注釋,不超過 140 字(可選)

        2. 叔結(jié)點(diǎn)是黑色的且新結(jié)點(diǎn)是左子樹

        • 以父結(jié)點(diǎn)為中心右旋
        • 將父結(jié)點(diǎn)變黑色,爺結(jié)點(diǎn)變紅色
        • 以爺結(jié)點(diǎn)為中心左旋

        添加圖片注釋,不超過 140 字(可選)

        3. 叔結(jié)點(diǎn)是黑色的且新結(jié)點(diǎn)是右子樹

        • 將父結(jié)點(diǎn)變成黑色,爺結(jié)點(diǎn)變成紅色
        • 以爺結(jié)點(diǎn)為中心左旋

        添加圖片注釋,不超過 140 字(可選)

        維護(hù)代碼

        //修復(fù)第4條性質(zhì)void rbtree_insert_fixup(rbtree *T, rbtree_node *z) { while (z->parent->color == RED) {//父結(jié)點(diǎn)是紅色的,需要調(diào)整 if (z->parent == z->parent->parent->left) {//如果父結(jié)點(diǎn)是爺結(jié)點(diǎn)是左子樹 rbtree_node *y = z->parent->parent->right;//叔結(jié)點(diǎn) if (y->color == RED) {//叔結(jié)點(diǎn)是紅色的 //先變色,叔,父變黑 z->parent->color = BLACK; y->color = BLACK; //爺結(jié)點(diǎn)變紅 z->parent->parent->color = RED; //下面的調(diào)整完了,調(diào)整上面 z = z->parent->parent; } else {//叔父結(jié)點(diǎn)是黑色 if (z == z->parent->right) {//新節(jié)點(diǎn)是在右邊 z = z->parent; rbtree_left_rotate(T, z); } z->parent->color = BLACK; z->parent->parent->color = RED; rbtree_right_rotate(T, z->parent->parent); } } else { // 如果父結(jié)點(diǎn)是爺結(jié)點(diǎn)是右子樹 rbtree_node *y = z->parent->parent->left;//叔父結(jié)點(diǎn) if (y->color == RED) {//叔父結(jié)點(diǎn)是紅色的 //先變色,叔,父變黑 z->parent->color = BLACK; y->color = BLACK; //爺結(jié)點(diǎn)變紅 z->parent->parent->color = RED; //下面的調(diào)整完了,調(diào)整上面 z = z->parent->parent; } else {//叔父結(jié)點(diǎn)是黑色 if (z == z->parent->left) {//新節(jié)點(diǎn)是在左邊 z = z->parent; rbtree_right_rotate(T, z); } z->parent->color = BLACK; z->parent->parent->color = RED; rbtree_left_rotate(T, z->parent->parent); } } } //最后別忘了根節(jié)點(diǎn)始終是黑色 T->root->color = BLACK;}

        紅黑樹刪除結(jié)點(diǎn)與刪除維護(hù)紅黑樹的四種情況

        刪除結(jié)點(diǎn)

        我們定義:

        • 覆蓋結(jié)點(diǎn):z(被指定刪除的結(jié)點(diǎn),實(shí)際上被覆蓋)
        • 刪除結(jié)點(diǎn):y(實(shí)際上被刪除的結(jié)點(diǎn),一般是后繼結(jié)點(diǎn))
        • 軸心結(jié)點(diǎn):x(維護(hù)紅黑樹的結(jié)點(diǎn))

        紅黑樹刪除結(jié)點(diǎn)根據(jù)改結(jié)點(diǎn)的左右子樹分為三種情況:

      22. 沒有左右子樹
      23. 有且僅有一個(gè)子樹
      24. 左右子樹都有
      25. 對(duì)不同情況的處理:

        • 情況1:直接刪除該結(jié)點(diǎn)
        • 情況2:將該結(jié)點(diǎn)的唯一子樹掛到父結(jié)點(diǎn)上,然后刪除該結(jié)點(diǎn)
        • 情況3:找一個(gè)刪除結(jié)點(diǎn)y(后繼結(jié)點(diǎn))覆蓋 指定結(jié)點(diǎn)z,然后刪除 刪除結(jié)點(diǎn)y,對(duì)于這個(gè)刪除結(jié)點(diǎn)y來說,它的情況一定是情況1或情況2

        刪除代碼

        rbtree_node *rbtree_mini(rbtree *T, rbtree_node *x) { while (x->left != T->nil) { x = x->left; } return x;}//找后繼結(jié)點(diǎn)rbtree_node *rbtree_successor(rbtree *T, rbtree_node *x) { rbtree_node *y = x->parent; //右子樹不為空,則找右子樹中最左的元素 if (x->right != T->nil) { return rbtree_mini(T, x->right); } //找到結(jié)點(diǎn)第一個(gè)父結(jié)點(diǎn) while ((y != T->nil) && (x == y->right)) { x = y; y = y->parent; } return y;}//覆蓋結(jié)點(diǎn)z//刪除結(jié)點(diǎn)y//軸心結(jié)點(diǎn)xrbtree_node *rbtree_delete(rbtree *T, rbtree_node *z) { rbtree_node *y = T->nil; rbtree_node *x = T->nil; if ((z->left == T->nil) || (z->right == T->nil)) { y = z;//如果沒有孩子或只有一個(gè) } else {//如果有兩個(gè)子樹則找后繼 y = rbtree_successor(T, z); } //一般x是y的右子樹,找到軸心結(jié)點(diǎn) if (y->left != T->nil) { x = y->left; } else if (y->right != T->nil) { x = y->right; } //將該結(jié)點(diǎn)的唯一子樹掛到父結(jié)點(diǎn)上,然后刪除該結(jié)點(diǎn) x->parent = y->parent; if (y->parent == T->nil) {//根結(jié)點(diǎn) T->root = x; } else if (y == y->parent->left) { y->parent->left = x; } else { y->parent->right = x; } //進(jìn)行覆蓋操作 if (y != z) { z->key = y->key; z->value = y->value; } //黑色才需要調(diào)整 if (y->color == BLACK) { rbtree_delete_fixup(T, x); } return y;}

        刪除結(jié)點(diǎn)后維護(hù)紅黑樹

        ??想一想,刪除一個(gè)結(jié)點(diǎn),該結(jié)點(diǎn)是什么顏色的時(shí)候才需要維護(hù)紅黑樹呢?

        • 如果是紅色,沒有違反任何性質(zhì)。所以如果是紅色直接刪除即可,無需維護(hù)
        • 如果是黑色,黑色被刪除,那么必定違反第5條性質(zhì),破壞了黑高,所以我們需要針對(duì)這一情況進(jìn)行維護(hù)

        ??如果當(dāng)前結(jié)點(diǎn)是父結(jié)點(diǎn)的左子樹的情況,可以歸納出來四種情況。同理如果當(dāng)前結(jié)點(diǎn)是父結(jié)點(diǎn)的右子樹,我們也可以歸納出來四種情況。但是這四種情況的差異就是旋轉(zhuǎn)方向的區(qū)別而已(鏡像的)。一共是8種情況,但是歸納出來其實(shí)是4種,讀者不要搞錯(cuò)了。

        當(dāng)前結(jié)點(diǎn)是父結(jié)點(diǎn)的左子樹的情況

        1.當(dāng)前結(jié)點(diǎn)的兄弟結(jié)點(diǎn)是紅色的

        • 兄弟節(jié)點(diǎn)變成黑色
        • 父節(jié)點(diǎn)變成紅色
        • 父節(jié)點(diǎn)做左旋
        • 將兄弟結(jié)點(diǎn)調(diào)整為父節(jié)點(diǎn)的右子樹

        添加圖片注釋,不超過 140 字(可選)

        2. 當(dāng)前結(jié)點(diǎn)的兄弟結(jié)點(diǎn)是黑色的,而且兄弟結(jié)點(diǎn)的兩個(gè)孩子結(jié)點(diǎn)都是黑色的

        • 兄弟節(jié)點(diǎn)變成紅色
        • 軸心結(jié)點(diǎn)變?yōu)楦腹?jié)點(diǎn)

        添加圖片注釋,不超過 140 字(可選)

        3. 當(dāng)前結(jié)點(diǎn)的兄弟結(jié)點(diǎn)是黑色的,而且兄弟結(jié)點(diǎn)的左孩子是紅色的,右孩子是黑色的

        • 將左孩子涂黑
        • 將兄弟節(jié)點(diǎn)變紅
        • 對(duì)兄弟節(jié)點(diǎn)右旋
        • 將兄弟結(jié)點(diǎn)調(diào)整為父節(jié)點(diǎn)的右子樹
        • 現(xiàn)在情況3就會(huì)變成情況4,接著做情況4的步驟

        添加圖片注釋,不超過 140 字(可選)

        4. 當(dāng)前結(jié)點(diǎn)的兄弟結(jié)點(diǎn)是黑色的,而且兄弟結(jié)點(diǎn)的左孩子是黑色的,右孩子是紅色的

        • 將兄弟節(jié)點(diǎn)換成父節(jié)點(diǎn)的顏色
        • 把父節(jié)點(diǎn)和兄弟節(jié)點(diǎn)的右孩子涂黑
        • 對(duì)父節(jié)點(diǎn)做左旋
        • 設(shè)置x指針,指向根節(jié)點(diǎn)

        添加圖片注釋,不超過 140 字(可選)

        當(dāng)前結(jié)點(diǎn)是父結(jié)點(diǎn)的右子樹的情況

        1. 當(dāng)前結(jié)點(diǎn)的兄弟結(jié)點(diǎn)是紅色的

        • 兄弟節(jié)點(diǎn)變成黑色
        • 父節(jié)點(diǎn)變成紅色
        • 父節(jié)點(diǎn)做右旋
        • 將兄弟結(jié)點(diǎn)調(diào)整為父節(jié)點(diǎn)的左子樹

        2. 當(dāng)前結(jié)點(diǎn)的兄弟結(jié)點(diǎn)是黑色的,而且兄弟結(jié)點(diǎn)的兩個(gè)孩子結(jié)點(diǎn)都是黑色的

        • 兄弟節(jié)點(diǎn)變成紅色
        • 軸心結(jié)點(diǎn)變?yōu)楦腹?jié)點(diǎn)

        3. 當(dāng)前結(jié)點(diǎn)的兄弟結(jié)點(diǎn)是黑色的,而且兄弟結(jié)點(diǎn)的左孩子是黑色的,右孩子是紅色的

        • 將右孩子變黑
        • 將兄弟節(jié)點(diǎn)變紅
        • 對(duì)兄弟結(jié)點(diǎn)左旋
        • 將兄弟結(jié)點(diǎn)調(diào)整為父節(jié)點(diǎn)的左子樹
        • 現(xiàn)在情況3就會(huì)變成情況4,接著做情況4的步驟

        4. 當(dāng)前結(jié)點(diǎn)的兄弟結(jié)點(diǎn)是黑色的,而且兄弟結(jié)點(diǎn)的左孩子是紅色的,右孩子是黑色的

        • 將兄弟節(jié)點(diǎn)換成父節(jié)點(diǎn)的顏色
        • 把父節(jié)點(diǎn)和兄弟節(jié)點(diǎn)的左孩子變黑
        • 對(duì)父節(jié)點(diǎn)做右旋
        • 將軸心結(jié)點(diǎn)調(diào)整為根結(jié)點(diǎn)

        維護(hù)代碼

        void rbtree_delete_fixup(rbtree *T, rbtree_node *x) { //如果x是紅色,變成黑色,如果x是黑色,需要調(diào)整 while ((x != T->root) && (x->color == BLACK)) { //當(dāng)前結(jié)點(diǎn)是父結(jié)點(diǎn)的左子樹 if (x == x->parent->left) { //兄弟節(jié)點(diǎn) rbtree_node *w = x->parent->right; // 情況1:兄弟節(jié)點(diǎn)為紅色 if (w->color == RED) { // 兄弟節(jié)點(diǎn)變成黑色 w->color = BLACK; // 父節(jié)點(diǎn)變成紅色 x->parent->color = RED; // 父節(jié)點(diǎn)做左旋 rbtree_left_rotate(T, x->parent); //將兄弟結(jié)點(diǎn)調(diào)整為父節(jié)點(diǎn)的右子樹 w = x->parent->right; } // 情況2:兄弟節(jié)點(diǎn)是黑色的,且兄弟的左孩子和右孩子都是黑色 if ((w->left->color == BLACK) && (w->right->color == BLACK)) { // 兄弟節(jié)點(diǎn)變成紅色 w->color = RED; // 軸心結(jié)點(diǎn)變?yōu)楦腹?jié)點(diǎn) x = x->parent; } else { // 情況3:x的兄弟節(jié)點(diǎn)是黑色的,兄弟的左孩子是紅色,右孩子是黑色 if (w->right->color == BLACK) { // 將左孩子涂黑 w->left->color = BLACK; // 將兄弟節(jié)點(diǎn)變紅 w->color = RED; // 對(duì)兄弟節(jié)點(diǎn)右旋 rbtree_right_rotate(T, w); // 重新設(shè)置x的兄弟節(jié)點(diǎn) w = x->parent->right; } // 情況4:x的兄弟節(jié)點(diǎn)是黑色;x的兄弟節(jié)點(diǎn)的右孩子是紅色的 // 將兄弟節(jié)點(diǎn)換成父節(jié)點(diǎn)的顏色 w->color = x->parent->color; // 把父節(jié)點(diǎn)和兄弟節(jié)點(diǎn)的右孩子涂黑 x->parent->color = BLACK; w->right->color = BLACK; // 對(duì)父節(jié)點(diǎn)做左旋 rbtree_left_rotate(T, x->parent); // 設(shè)置x指針,指向根節(jié)點(diǎn) x = T->root; } } else {//當(dāng)前結(jié)點(diǎn)是父結(jié)點(diǎn)的右子樹 //兄弟節(jié)點(diǎn) rbtree_node *w = x->parent->left; //情況1:兄弟結(jié)點(diǎn)為紅色 if (w->color == RED) { // 兄弟節(jié)點(diǎn)變成黑色 w->color = BLACK; // 父節(jié)點(diǎn)變成紅色 x->parent->color = RED; // 父節(jié)點(diǎn)做右旋 rbtree_right_rotate(T, x->parent); //將兄弟結(jié)點(diǎn)調(diào)整為父節(jié)點(diǎn)的左子樹 w = x->parent->left; } // 情況2:兄弟節(jié)點(diǎn)是黑色的,且兄弟的左孩子和右孩子都是黑色 if ((w->left->color == BLACK) && (w->right->color == BLACK)) { // 兄弟節(jié)點(diǎn)變成紅色 w->color = RED; // 軸心結(jié)點(diǎn)變?yōu)楦腹?jié)點(diǎn) x = x->parent; } else { // 情況3:x的兄弟結(jié)點(diǎn)是黑色的,兄弟的左孩子是黑色,右孩子是紅色 if (w->left->color == BLACK) { //將右孩子變黑 w->right->color = BLACK; //將兄弟節(jié)點(diǎn)變紅 w->color = RED; //對(duì)兄弟結(jié)點(diǎn)左旋 rbtree_left_rotate(T, w); //將兄弟結(jié)點(diǎn)調(diào)整為父節(jié)點(diǎn)的左子樹 w = x->parent->left; } // 情況4:x的兄弟結(jié)點(diǎn)是黑色的,兄弟的左孩子是紅色,右孩子是黑色 // 將兄弟節(jié)點(diǎn)換成父節(jié)點(diǎn)的顏色 w->color = x->parent->color; // 把父節(jié)點(diǎn)和兄弟節(jié)點(diǎn)的左孩子變黑 x->parent->color = BLACK; w->left->color = BLACK; // 對(duì)父節(jié)點(diǎn)做右旋 rbtree_right_rotate(T, x->parent); //將軸心結(jié)點(diǎn)調(diào)整為根結(jié)點(diǎn) x = T->root; } } } // 繼承節(jié)點(diǎn)變?yōu)楹谏?,為了彌補(bǔ)失去的黑高 x->color = BLACK;}

        紅黑樹的遍歷、查詢、測(cè)試

        rbtree_node *rbtree_search(rbtree *T, KEY_TYPE key) { rbtree_node *node = T->root; while (node != T->nil) { if (key key) { node = node->left; } else if (key > node->key) { node = node->right; } else { return node; } } return T->nil;}void rbtree_traversal(rbtree *T, rbtree_node *node) { if (node != T->nil) { rbtree_traversal(T, node->left); printf(“key:%d, color:%d”, node->key, node->color); rbtree_traversal(T, node->right); }}int main() { int keyArray[20] = {24, 25, 13, 35, 23, 26, 67, 47, 38, 98, 20, 19, 17, 49, 12, 21, 9, 18, 14, 15}; rbtree *T = (rbtree *) malloc(sizeof(rbtree)); if (T == NULL) { printf(“malloc failed”); return -1; } T->nil = (rbtree_node *) malloc(sizeof(rbtree_node)); T->nil->color = BLACK; T->root = T->nil; rbtree_node *node = T->nil; int i = 0; for (i = 0; i key = keyArray[i]; node->value = NULL; rbtree_insert(T, node); } rbtree_traversal(T, T->root); printf(“—————————————-“); for (i = 0; i root); printf(“—————————————-“); }}

        原文鏈接:隨處可見的紅黑樹詳解_cheems~的博客-CSDN博客

        鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場(chǎng),版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
        上一篇 2022年7月12日 15:26
        下一篇 2022年7月12日 15:26

        相關(guān)推薦

        聯(lián)系我們

        聯(lián)系郵箱:admin#wlmqw.com
        工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息