• 红黑树之插入实现


    红黑树

    性质

    1. 红黑树的结点都是红色或者黑色
    2. 根结点是黑色
    3. 所有叶子都是黑色(这里的叶子结点是空结点)
    4. 每个红色结点必须有两个黑色的子结点
    5. 从任何一个节点到其每个叶子的所有简单路径都包含相同数目的黑色结点

    • 性质1和性质3总是能够保持着;
    • 性质4只有在这些情况下才会发生作用:
      • 增加红色结点
      • 将黑色结点重新绘制成红色结点
      • 旋转
    • 性质5在这些情况下才会发生作用:
      • 增加黑色结点
      • 将红色结点重新绘制黑色结点
      • 旋转

    举例:

    插入

    用BST的方法将结点插入,将该结点标记为红色的(因为如果标记为黑色,则会导致根结点到叶子结点的路径会多出一个黑结点,无法满足性质5,而且不容易进行调整),插入的情况包括下面几种:

    1. 插入到一个空的树,插入结点则为根结点,只需要将红色结点重新转染成黑色结点来满足性质2;
    2. 新结点的父结点为黑色,满足所有条件;
    3. 新结点的父结点为红色,因为性质2和性质4,所以树必然有祖父结点,则又包括以下的情况:
      1. 父亲结点和叔父结点均为红色,显然无法满足性质4,则将父亲结点和叔父结点绘制成黑色,祖父结点设置成红色,但是仍然无法满足情况,比如考虑到祖父结点可能是根结点,则无法满足性质2,或者祖父结点的父结点是红色的,则无法满足性质4,这时需要将祖父结点作为新的结点来看待进行各种情况的判断,涉及到对祖父结点的递归;

      2. 父亲结点为红色同时叔父结点为黑色或者从缺,这里又分为两种情况,新插入结点为父亲结点的左子结点和右子结点(假设其中父亲结点为祖父结点的左子结点),区别在于旋转的方向,显然,这棵树父亲结点既然为红色,那么其祖父结点则为黑色(性质4),不然无法满足前提。
        1. 新插入结点为父亲结点的左子结点,那么就构成了一个左左的情况,在之前平衡树中提到过,如果要将其进行平衡,则需要对父结点进行一次单右旋转,形成一个父亲结点为相对根结点,子结点和祖父结点为子结点的树,同时将父亲结点的红色改为黑色,祖父结点更改为红色,这下之前无法满足的性质4和性质5就满足了;

        2. 新插入结点为父亲结点的右子结点,那么就会构成一个左右的情况,在之前的平衡树也提到过要进行一次双旋转,先对新结点进行一次单左旋转,变成了左左的结构,再进行一次单右旋转,从而达到满足所有性质;

      3. 父亲结点是祖父结点的右结点,参考平衡树进行相应的操作,原理是一致的

    实现

    自然先看头文件,如下:

      1 typedef enum {
      2     RB_RED = 0,
      3     RB_BLACK
      4 } RBColor;
      5 
      6 struct RBTreeNode {
      7     RBColor rb_color;
      8     int rb_key;
      9     struct RBTreeNode *rb_left;
     10     struct RBTreeNode *rb_right;
     11     struct RBTreeNode *rb_parent;
     12 
     13     RBTreeNode(int key) : rb_key(key), rb_color(RB_BLACK), rb_left(nullptr), rb_right(nullptr), rb_parent(nullptr) {}
     14 };
     15 
     16 struct RBTreeRoot {
     17     struct RBTreeNode* rb_node;
     18 };
     19 
     20 class RBTree {
     21 public:
     22     RBTree();
     23     ~RBTree();
     24 
     25     void insert(int val);
     26     void print();
     27 private:
     28     void _left_rotate(struct RBTreeRoot *root, struct RBTreeNode* node);
     29     void _right_rotate(struct RBTreeRoot *root, struct RBTreeNode* node);
     30     RBTreeNode* insert_node(struct RBTreeNode* node);
     31     void _insert_node(struct RBTreeNode* node);
     32     void _print(struct RBTreeNode* root);
     33 
     34     struct RBTreeRoot* _root;
     35 };
     36 当然,为了使用更方便,还定义了一些红定义和内联函数;
     37 #define rb_parent(r)    ((struct RBTreeNode *)((r)->rb_parent))
     38 #define rb_color(r)     ((r)->rb_color)
     39 #define rb_is_red(r)    ((r)->rb_color & RB_RED)
     40 #define rb_is_black(r)  ((r)->rb_color & RB_BLACK)
     41 #define rb_set_red(r)   ((r)->rb_color = RB_RED)
     42 #define rb_set_black(r) ((r)->rb_color = RB_BLACK)
     43 
     44 static inline void rb_set_reds(int count, ...) {
     45     va_list args;
     46     va_start(args, count);
     47     while (count--) {
     48         rb_set_red(va_arg(args, struct RBTreeNode*));
     49     }
     50     va_end(args);
     51 }
     52 
     53 static inline void rb_set_blacks(int count, ...) {
     54     va_list args;
     55     va_start(args, count);
     56     while (count--) {
     57         rb_set_black(va_arg(args, struct RBTreeNode*));
     58     }
     59     va_end(args);
     60 }
     61 
     62 static inline void rb_set_parent(struct RBTreeNode* cb, struct RBTreeNode* p) {
     63     cb->rb_parent = p;
     64 }
     65 
     66 static inline void rb_set_left(struct RBTreeNode* cb, struct RBTreeNode* p) {
     67     cb->rb_left = p;
     68     rb_set_parent(p, cb);
     69 }
     70 
     71 static inline void rb_set_right(struct RBTreeNode* cb, struct RBTreeNode* p) {
     72     cb->rb_right = p;
     73     rb_set_parent(p, cb);
     74 }
     75 
     76 static inline bool rb_is_left(struct RBTreeNode* cb, struct RBTreeNode* p) {
     77     return p->rb_left == cb;
     78 }
     79 
     80 static inline bool rb_is_right(struct RBTreeNode* cb, struct RBTreeNode* p) {
     81     return p->rb_right == cb;
     82 }
     83 真正的实现在这里,其操作可以参考平衡二叉树:
     84 RBTree::RBTree() {
     85     _root = new RBTreeRoot();
     86 }
     87 
     88 RBTree::~RBTree() {
     89     delete _root;
     90 }
     91 
     92 /*
     93  * 对红黑树的节点(x)进行左旋转
     94  *
     95  * 左旋示意图(对节点x进行左旋):
     96  *      px                              px
     97  *     /                               /
     98  *    x                               y
     99  *   /        --(左旋)-->           /          #
    100  *  lx   y                          x  ry
    101  *     /                          /  
    102  *    ly   ry                     lx  ly
    103  *
    104  *
    105  */
    106 void RBTree::_left_rotate(struct RBTreeRoot *root, struct RBTreeNode *node) {
    107     struct RBTreeNode *right = node->rb_right, *parent = rb_parent(node);
    108 
    109     // 第一步:将ly连接到x的右结点上
    110     rb_set_right(node, right->rb_left);
    111 
    112     // 第二步:将x设置为y的左子结点
    113     rb_set_left(right, node);
    114 
    115     // 第三步:将y设置为px的子结点
    116     if (parent) {
    117         if (rb_is_left(node, parent)) {
    118             rb_set_left(right, parent);
    119         }
    120         else {
    121             rb_set_right(right, parent);
    122         }
    123     }
    124     else {
    125         root->rb_node = right; // 根结点
    126     }
    127 }
    128 
    129 /*
    130  * 对红黑树的节点(y)进行右旋转
    131  *
    132  * 右旋示意图(对节点y进行左旋):
    133  *            py                               py
    134  *           /                                /
    135  *          y                                x
    136  *         /        --(右旋)-->            /                       #
    137  *        x   ry                           lx   y
    138  *       /                                    /                    #
    139  *      lx  rx                                rx  ry
    140  *
    141  */
    142 void RBTree::_right_rotate(struct RBTreeRoot *root, struct RBTreeNode *node) {
    143     struct RBTreeNode *left = node->rb_left, *parent = rb_parent(node);
    144 
    145     // 第一步:将rx设置为y的左子结点
    146     rb_set_left(node, left->rb_right);
    147 
    148     // 第二步:将y设置为x的右子结点
    149     rb_set_right(left, node);
    150 
    151     // 第三步:将x设置为py的子结点
    152     if (parent) {
    153         if (rb_is_left(node, parent)) {
    154             rb_set_left(parent, left);
    155         }
    156         else {
    157             rb_set_right(parent, left);
    158         }
    159     }
    160 }
    161 
    162 void RBTree::_insert_node(struct RBTreeNode *node) {
    163     struct RBTreeNode *parent, *g_parent;
    164 
    165     // 满足性质4
    166     while ((parent = rb_parent(node)) && rb_is_red(parent)) {
    167         g_parent = rb_parent(parent);
    168 
    169         if (rb_is_left(parent, g_parent)) {
    170             {
    171                 // case 1:叔叔结点是红色
    172                 // 寄存器变量,提高效率
    173                 struct RBTreeNode *uncle = g_parent->rb_right;
    174                 // 无法满足性质4
    175                 if (uncle && rb_is_red(uncle)) {
    176                     // step1:将父亲和叔叔结点设置成黑色
    177                     rb_set_blacks(2, parent, uncle);
    178                     // step2:将祖父设置成红色(因为之前必然为黑色,不然无法满足性质4)
    179                     rb_set_red(g_parent);
    180                     // step3:递归检查祖父结点
    181                     node = g_parent;
    182                     continue;
    183                 }
    184             }
    185 
    186             // 无法满足性质5
    187             // case 2:叔叔结点是黑色,并且当前结点在右边,必然要进行双旋转
    188             if (rb_is_right(node, parent)) {
    189                 struct RBTreeNode *temp;
    190 
    191                 // step 1:将父亲结点进行左旋
    192                 _left_rotate(_root, parent); // 此时父结点为当前结点的左子结点
    193                 // step 2:将当前结点和父结点进行交换
    194                 temp = parent;
    195                 parent = node;
    196                 node = temp;
    197             }
    198 
    199             // 此时父亲结点和当前结点均是红色,无法满足性质4和性质5
    200             // case 3:叔叔结点是黑色,并且当前结点在左边,只用单旋转
    201             // step 1:将父亲结点改成改成黑色,祖父结点改成红色,以便后面进行旋转后,
    202             // 红色的左子结点和祖父结点为黑色的父结点的子结点
    203             rb_set_black(parent);
    204             rb_set_red(g_parent);
    205             // step 2:右旋转
    206             _right_rotate(_root, g_parent);  // 经过右旋转后,红色均分布在两边
    207         }
    208         else {  // 顺序相反而已
    209             {
    210                 // case 4:叔叔结点是红色
    211                 // 寄存器变量,提高效率
    212                 struct RBTreeNode *uncle = g_parent->rb_left;
    213                 // 无法满足性质4
    214                 if (uncle && rb_is_red(uncle)) {
    215                     // step1:将父亲和叔叔结点设置成黑色
    216                     rb_set_blacks(2, parent, uncle);
    217                     // step2:将祖父设置成红色(因为之前必然为黑色,不然无法满足性质4)
    218                     rb_set_red(g_parent);
    219                     // step3:递归检查祖父结点
    220                     node = g_parent;
    221                     continue;
    222                 }
    223             }
    224 
    225             // 无法满足性质5
    226             // case 5:叔叔结点是黑色,并且当前结点在左边,必然要进行双旋转
    227             if (rb_is_left(node, parent)) {
    228                 struct RBTreeNode *temp;
    229 
    230                 // step 1:将父亲结点进行左旋
    231                 _right_rotate(_root, parent); // 此时父结点为当前结点的右子结点
    232                 // step 2:将当前结点和父结点进行交换
    233                 temp = parent;
    234                 parent = node;
    235                 node = temp;
    236             }
    237 
    238             // 此时父亲结点和当前结点均是红色,无法满足性质4和性质5
    239             // case 3:叔叔结点是黑色,并且当前结点在右边,只用单旋转
    240             // step 1:将父亲结点改成改成黑色,祖父结点改成红色,以便后面进行旋转后,
    241             // 红色的左子结点和祖父结点为黑色的父结点的子结点
    242             rb_set_black(parent);
    243             rb_set_red(g_parent);
    244             // step 2:左旋转
    245             _left_rotate(_root, g_parent);  // 经过左旋转后,红色均分布在两边
    246         }
    247     }
    248 }
    249 
    250 // 参照BST的插入方法
    251 RBTreeNode* RBTree::insert_node(struct RBTreeNode *node) {
    252     struct RBTreeNode* temp = _root->rb_node;
    253     struct RBTreeNode* temp_parent = nullptr;
    254 
    255     while (temp != nullptr) {
    256         temp_parent = temp;
    257         if (node->rb_key < temp->rb_key) {
    258             temp = temp->rb_left;
    259         }
    260         else {
    261             temp = temp->rb_right;
    262         }
    263     }
    264 
    265     // 设置子结点
    266     if (temp_parent != nullptr) {
    267         if (node->rb_key < temp_parent->rb_key) {
    268             rb_set_left(temp_parent, node);
    269         }
    270         else {
    271             rb_set_right(temp_parent, node);
    272         }
    273     }
    274     else {
    275         _root->rb_node = node;  // 根结点
    276     }
    277 
    278     return node;
    279 }
    280 
    281 void RBTree::insert(int val) {
    282     struct RBTreeNode* node = new RBTreeNode(val);
    283     node = this->insert_node(node);
    284     this->_insert_node(node);
    285 }
    286 
    287 void RBTree::_print(struct RBTreeNode* root) {
    288     if (root->rb_left) {
    289         _print(root->rb_left);
    290     }
    291     std::cout << root->rb_key << "   ";
    292     if (root->rb_right) {
    293         _print(root->rb_right);
    294     }
    295 }
    296 
    297 void RBTree::print() {
    298     _print(_root->rb_node);
    299 }
  • 相关阅读:
    Perl Resources
    使用Perl管理Oracle数据库
    Tomcat 发布部署jsp网站—-使用自己的ip访问jsp网站
    Lode's Computer Graphics Tutorial Image Filtering
    Java Image Filters
    ZPhotoEngine超级算法库
    ps亮度对比度算法
    滤镜艺术---新海诚(你的名字)滤镜特效的实现解密
    Cocoa-GL-Tutorial
    Learning Cocoa with Objective-C
  • 原文地址:https://www.cnblogs.com/shilinnpu/p/8876951.html
Copyright © 2020-2023  润新知