红黑树
性质
- 红黑树的结点都是红色或者黑色
- 根结点是黑色
- 所有叶子都是黑色(这里的叶子结点是空结点)
- 每个红色结点必须有两个黑色的子结点
- 从任何一个节点到其每个叶子的所有简单路径都包含相同数目的黑色结点
- 性质1和性质3总是能够保持着;
- 性质4只有在这些情况下才会发生作用:
- 增加红色结点
- 将黑色结点重新绘制成红色结点
- 旋转
- 性质5在这些情况下才会发生作用:
- 增加黑色结点
- 将红色结点重新绘制黑色结点
- 旋转
举例:
插入
用BST的方法将结点插入,将该结点标记为红色的(因为如果标记为黑色,则会导致根结点到叶子结点的路径会多出一个黑结点,无法满足性质5,而且不容易进行调整),插入的情况包括下面几种:
- 插入到一个空的树,插入结点则为根结点,只需要将红色结点重新转染成黑色结点来满足性质2;
- 新结点的父结点为黑色,满足所有条件;
- 新结点的父结点为红色,因为性质2和性质4,所以树必然有祖父结点,则又包括以下的情况:
-
父亲结点和叔父结点均为红色,显然无法满足性质4,则将父亲结点和叔父结点绘制成黑色,祖父结点设置成红色,但是仍然无法满足情况,比如考虑到祖父结点可能是根结点,则无法满足性质2,或者祖父结点的父结点是红色的,则无法满足性质4,这时需要将祖父结点作为新的结点来看待进行各种情况的判断,涉及到对祖父结点的递归;
- 父亲结点为红色同时叔父结点为黑色或者从缺,这里又分为两种情况,新插入结点为父亲结点的左子结点和右子结点(假设其中父亲结点为祖父结点的左子结点),区别在于旋转的方向,显然,这棵树父亲结点既然为红色,那么其祖父结点则为黑色(性质4),不然无法满足前提。
-
新插入结点为父亲结点的左子结点,那么就构成了一个左左的情况,在之前平衡树中提到过,如果要将其进行平衡,则需要对父结点进行一次单右旋转,形成一个父亲结点为相对根结点,子结点和祖父结点为子结点的树,同时将父亲结点的红色改为黑色,祖父结点更改为红色,这下之前无法满足的性质4和性质5就满足了;
-
新插入结点为父亲结点的右子结点,那么就会构成一个左右的情况,在之前的平衡树也提到过要进行一次双旋转,先对新结点进行一次单左旋转,变成了左左的结构,再进行一次单右旋转,从而达到满足所有性质;
-
-
父亲结点是祖父结点的右结点,参考平衡树进行相应的操作,原理是一致的
-
实现
自然先看头文件,如下:
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 }