• RedBlack-Tree(红黑树)原理及C++代码实现


    众所周知,红黑树是用途很广的平衡二叉搜索树,用过的都说好。所以我们来看看红黑树的是怎么实现的吧。

    红黑树顾名思义,通过红与黑两种颜色来给每个节点上色。其中根结点和叶子结点一定是黑色的,并且红色结点的两个孩子一定是黑色的,每个结点到所有后代叶子的简单路径上,均包含相同数目的黑色结点(黑高bh)。

    这里和其他树有些区别的是,红黑树的叶子结点并不包含关键字,它只是用来维持红黑树的性质。所以包含关键字的结点都是内部结点。

    这样的性质也带来了很多有意思的现象。下面我们忽略所谓的叶子结点来看看。

    1.红色结点的孩子要么没有,要么是两个黑色结点,不会有单个孩子结点的时候。

    2.如果某个结点只有一个孩子结点,那么那个孩子结点一定是红色的。

    3.用吸收的角度去看,即黑色结点可以吸收它的红色孩子结点,红黑树就像一个2-3-4树。

    下面我们来看看代码吧,代码用了一个小技巧,即所有的叶子结点都用一个nil结点来表示,指向nullptr的指针现在全部指向nil。

    代码如下:(仅供参考)

      1 #include <iostream>
      2 using namespace std;
      3 
      4 class RBT {
      5 private :
      6     enum {RED = 0, BLACK};
      7     struct Node {
      8         int key;
      9         bool color;
     10         Node * left;
     11         Node * right;
     12         Node * parent;
     13         Node(int k = 0, bool c = BLACK, Node *l = nullptr, Node *r = nullptr, Node *p = nullptr)
     14             : key(k), color(c), left(l), right(r), parent(p) {}
     15     };
     16 private :
     17     Node * nil;
     18     Node * root;
     19 private :
     20     void leftRotate(Node * x);
     21     void rightRotate(Node * x);
     22     void fixup_insert(Node * p);
     23     void fixup_remove(Node * p);
     24     void transplant(Node * old_t, Node * new_t);
     25     void insert(Node * p);
     26     void remove(Node * p);
     27     Node * search(Node * p, const int k);
     28     Node * minimum(Node * p);
     29     Node * maximum(Node * p);
     30     void inorderWalk(Node * p) const;
     31 public :
     32     RBT() : nil(new Node), root(nil) {}
     33     ~RBT() {delete nil;}
     34     void insert(const int key) {insert(new Node(key, RED, nil, nil, nil));}
     35     void remove(const int key) {remove(search(root, key));}
     36     bool search(const int key) {return (search(root, key) == nil ? false : true);}
     37     int minimum() {return minimum(root)->key;}
     38     int maximum() {return maximum(root)->key;}
     39     int predecessor(const int key);
     40     int successor(const int key);
     41 
     42 friend ostream &operator<<(ostream &os, const RBT &t);
     43 };
     44 
     45 void RBT::inorderWalk(Node * p) const {
     46     if (p != nil) {
     47         inorderWalk(p->left);
     48         cout << p->key << ' ';
     49         inorderWalk(p->right);
     50     }
     51 }
     52 
     53 RBT::Node * RBT::search(Node * p, const int k) {
     54     if (p == nil || k == p->key)
     55         return p;
     56     if (k < p->key)
     57         return search(p->left, k);
     58     else
     59         return search(p->right, k);
     60 }
     61 
     62 RBT::Node * RBT::minimum(Node * p) {
     63     if (p == nil)
     64         return p;
     65     while (p->left != nil)
     66         p = p->left;
     67     return p;
     68 }
     69 
     70 RBT::Node * RBT::maximum(Node * p) {
     71     if (p == nil)
     72         return p;
     73     while (p->right != nil)
     74         p = p->right;
     75     return p;
     76 }
     77 
     78 int RBT::predecessor(const int k) {
     79     Node * p = search(root, k);
     80     if (p == nil)
     81         return 0;
     82     if (p->left != nil)
     83         return maximum(p->left)->key;
     84     Node * y = p->parent;
     85     while (y != nil && y->left == p) {
     86         p = y;
     87         y = y->parent;
     88     }
     89     return y->key;
     90 }
     91 
     92 int RBT::successor(const int k) {
     93     Node * p = search(root, k);
     94     if (p == nil)
     95         return 0;
     96     if (p->right != nil)
     97         return minimum(p->right)->key;
     98     Node * y = p->parent;
     99     while (y != nil && y->right == p) {
    100         p = y;
    101         y = y->parent;
    102     }
    103     return y->key;
    104 }
    105 
    106 void RBT::leftRotate(Node * x) { //assume:x->right != nil
    107     Node * y = x->right;
    108     x->right = y->left;
    109     if (y->left != nil)
    110         y->left->parent = x;
    111     y->parent = x->parent;
    112     if (x->parent == nil)
    113         root = y;
    114     else if (x == x->parent->left)
    115         x->parent->left = y;
    116     else
    117         x->parent->right = y;
    118     y->left = x;
    119     x->parent = y;
    120 }
    121 
    122 void RBT::rightRotate(Node * x) { //assume:x->left != nil
    123     Node * y = x->left;
    124     x->left = y->right;
    125     if (y->right != nil)
    126         y->right->parent = x;
    127     y->parent = x->parent;
    128     if (x->parent == nil)
    129         root = y;
    130     else if (x == x->parent->right)
    131         x->parent->right = y;
    132     else
    133         x->parent->left = y;
    134     y->right = x;
    135     x->parent = y;
    136 }
    137 
    138 void RBT::insert(Node * p) {
    139     if (p == nullptr)
    140         return ;
    141     Node * x = root;
    142     Node * y = nil;
    143     while (x != nil) {
    144         y = x;
    145         if (x->key < p->key)
    146             x = x->right;
    147         else
    148             x = x->left;
    149     }
    150     p->parent = y;
    151     if (y == nil)
    152         root = p;
    153     else if (y->key < p->key)
    154         y->right = p;
    155     else
    156         y->left = p;
    157     fixup_insert(p);
    158 }
    159 
    160 void RBT::fixup_insert(Node * p) {
    161     while (p->parent->color == RED) {
    162         if (p->parent == p->parent->parent->left) {
    163             Node * y = p->parent->parent->right;
    164             if (y->color == RED) { //case 1
    165                 p->parent->color = BLACK;
    166                 y->color = BLACK;
    167                 p->parent->parent->color = RED;
    168                 p = p->parent->parent;
    169             }
    170             else {
    171                 if (p == p->parent->right) { //case 2
    172                     p = p->parent;
    173                     leftRotate(p);
    174                 }
    175                 p->parent->color = BLACK; //case 3
    176                 p->parent->parent->color = RED;
    177                 rightRotate(p->parent->parent);
    178             }
    179         }
    180         else { //with "right" and "left" exchanged
    181             Node * y = p->parent->parent->left;
    182             if (y->color == RED) { //case 1
    183                 p->parent->color = BLACK;
    184                 y->color = BLACK;
    185                 p->parent->parent->color = RED;
    186                 p = p->parent->parent;
    187             }
    188             else {
    189                 if (p == p->parent->left) { //case 2
    190                     p = p->parent;
    191                     rightRotate(p);
    192                 }
    193                 p->parent->color = BLACK; //case 3
    194                 p->parent->parent->color = RED;
    195                 leftRotate(p->parent->parent);
    196             }
    197         }
    198     }
    199     root->color = BLACK;
    200 }
    201 
    202 void RBT::transplant(Node * old_t, Node * new_t) {
    203     if (old_t->parent == nil)
    204         root = new_t;
    205     else if (old_t == old_t->parent->left)
    206         old_t->parent->left = new_t;
    207     else
    208         old_t->parent->right = new_t;
    209     new_t->parent = old_t->parent;
    210 }
    211 
    212 void RBT::fixup_remove(Node * x) {
    213     Node * z = nil;
    214     while (x != root && x->color == BLACK) {
    215         if (x == x->parent->left) {
    216             z = x->parent->right;
    217 /*case 1*/  if (z->color == RED) {
    218                 z->color = BLACK;
    219                 x->parent->color = RED;
    220                 leftRotate(x->parent);
    221                 z = x->parent->right; //new z
    222             }
    223 /*case 2*/  if (z->left->color == BLACK && z->right->color == BLACK) {
    224                 z->color = RED;
    225                 x = x->parent;
    226             }
    227             else {
    228 /*case 3*/      if (z->right->color == BLACK) {
    229                     z->left->color = BLACK;
    230                     z->color = RED;
    231                     rightRotate(z);
    232                     z = x->parent->right;
    233                 }
    234 /*case 4*/      z->color = x->parent->color;
    235                 x->parent->color = BLACK;
    236                 z->right->color = BLACK;
    237                 leftRotate(x->parent);
    238                 x = root; //exit while
    239             }
    240         }
    241         else {
    242             z = x->parent->left;
    243 /*case 1*/  if (z->color == RED) {
    244                 z->color = BLACK;
    245                 x->parent->color = RED;
    246                 rightRotate(x->parent);
    247                 z = x->parent->left; //new z
    248             }
    249 /*case 2*/  if (z->right->color == BLACK && z->left->color == BLACK) {
    250                 z->color = RED;
    251                 x = x->parent;
    252             }
    253             else {
    254 /*case 3*/      if (z->left->color == BLACK) {
    255                     z->right->color = BLACK;
    256                     z->color = RED;
    257                     leftRotate(z);
    258                     z = x->parent->left;
    259                 }
    260 /*case 4*/      z->color = x->parent->color;
    261                 x->parent->color = BLACK;
    262                 z->left->color = BLACK;
    263                 rightRotate(x->parent);
    264                 x = root; //exit while
    265             }
    266         }
    267     }
    268     x->color = BLACK;
    269 }
    270 
    271 void RBT::remove(Node * p) {
    272     if (p == nil)
    273         return ;
    274     Node * y = p;
    275     Node * x = nil;
    276     bool y_originalColor = y->color;
    277     if (p->left == nil) {
    278         x = p->right;
    279         transplant(p, p->right);
    280     }
    281     else if (p->right == nil) {
    282         x = p->left;
    283         transplant(p, p->left);
    284     }
    285     else {
    286         y = minimum(p->right);
    287         y_originalColor = y->color;
    288         x = y->right;
    289         if (y->parent == p)
    290             x->parent = y;   //maybe x == nil
    291         else {
    292             transplant(y, y->right);
    293             y->right = p->right;
    294             y->right->parent = y;
    295         }
    296         transplant(p, y);
    297         y->left = p->left;
    298         y->left->parent = y;
    299         y->color = p->color;
    300     }
    301     delete p;
    302     if (y_originalColor == BLACK)
    303         fixup_remove(x);
    304 }
    305 
    306 ostream &operator<<(ostream &os, const RBT &t) {
    307     t.inorderWalk(t.root);
    308     return os;
    309 }
  • 相关阅读:
    浅谈P2P、P2C 、O2O 、B2C、B2B、 C2C的区别
    用CornerStone配置SVN,HTTP及svn简单使用说明
    Nginx之让用户通过用户名密码认证访问web站点
    linux下php redis扩展安装
    mac下用户用户组命令行操作
    linux下MySQL安装及设置(二)
    linux下MySQL安装及设置
    linux下php的一些问题
    计算多个文档之间的文本相似程度
    提取图像兴趣点
  • 原文地址:https://www.cnblogs.com/yxsrt/p/12201788.html
Copyright © 2020-2023  润新知