📂C/C++
🔖C++
2022-03-12 17:28阅读: 448评论: 0推荐: 1

C++实现红黑树

红黑树--RB_tree

  • 红黑树演示网站https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
  • 平衡树是指树的左右子树高度差不超过一,而红黑树是对黑色节点完全平衡的二叉搜索树。
  • 红黑树是从2-3-4 树变化而来,与AVL相比较平衡没有那么严格。
    • AVL对于平衡要求过高,面对插入与删除性能差。
  • 红黑树在C++中是实现set/multiset、map/multimap的底层容器。
  • 红黑树满足如下要求
    • 1.每个节点不是红色就是黑色
    • 2.根节点为黑色
    • 3.如果节点为红色,其子节点必为黑色
    • 4.任意节点至NULL节点(树尾端)的任何路径,所含黑色节点相同
    • 根据规则4可知,新增节点必须为红
    • 根据规则3可知,新增节点父节点必须为黑

A. 2-3-4 树

2-3-4树

  • 2-3-4树的介绍可参照heyanxi0101·234树
  • 由于红黑树是由2-3-4树来的,所以有以下转换关系。(红色与黑色结合,可恢复2-3-4树。但不能连着的两个黑色结合)
    红黑树与2-3-4树
  • 二节点对应红黑树的一个红色节点(当该节点为根时,为黑色节点)。
  • 三节点对应的必是上黑下红。
  • 四节点转换后对应如图。

  • 当新增一个节点时,对应关系如下图
    红黑树新增节点情况
  • 需要注意的是三节点的操作,需要调整到图示最终的对应结果。
    • 当伯父节点为黑色时,该节点不是与祖父一起的,其实还是三节点。
    • 三节点只需一次(外则插入)或者两次(内侧插入)左右旋即可。
  • 当四节点调整完后,若祖祖父还是红色,即两个红色挨着,需要继续向上调整,直到不再有连续红色。

B. 红黑树的插入

  • 根据上述图的描述,可以得到如下对树的平衡规则。父节点为当前(未平衡前的)插入节点的父节点。插入的节点为红色。
    • 当父节点为黑色时,不调整树。即上图中新增一个节点到二节点情况。
    • 当父节点为红色时,伯父节点不存在(或为黑色),需要左旋与右旋操作,调整成上图新增一个节点到三节点的最终结果。
      • NULL节点其实就可以当作黑色节点。
    • 当父节点为红色时,伯父节点为红色,只需交换颜色即可。如上图新增一个节点到四节点所示。
      • 若祖父为根节点,则变为黑色。
      • 但当祖父与祖祖父都为红色时,需要再次向上处理,直到不再有父子连续为红的情况。

B1. 树的左右旋

左右旋

rightRatote、leftRatote
copy
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
/* root root parent node / \ / \ node brother ---> left parent / \ / \ left right right brother */ template <typename value> void rb_tree<value>::rightRatote(pointer node) { if (!node || !parent(node)) //空节点或没有父节点 return; pointer root = parent(parent(node)); //祖父节点 left(parent(node)) = right(node); if (right(node) != nullptr) right(node)->parent = parent(node); parent(parent(node)) = node; right(node) = parent(node); parent(node) = root; if (!root)//若root为空,即parent是根节点 header = node; else if (value(node) <= value(root))//判断时否是root的左节点 left(root) = node; else right(root) = node; } /* root root node parent / \ / \ parent right <--- brother node / \ / \ brother left left right */ template <typename Value> void rb_tree<Value>::leftRatote(pointer node) { if (!node || !parent(node)) //空节点或没有父节点 return; pointer root = parent(parent(node)); right(parent(node)) = left(node); if (left(node) != nullptr) left(node)->parent = parent(node); parent(parent(node)) = node; left(node) = parent(node); parent(node) = root; if (!root)//若root为空,即parent是根节点 header = node; else if (value(node) <= value(root)) left(root) = node; else right(root) = node; }

B2. 二叉树搜索树的插入

  • 需要先将新节点插入到指定位置,再进行平衡。此处代码是不可插入重复值。
insert_unique
copy
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
template <typename Value> bool rb_tree<Value>::insert_unique(value_type v) { pointer ptr = new node_type; //创建一个节点 value(ptr) = v; //初始化该值 left(ptr) = nullptr; right(ptr) = nullptr; parent(ptr) = nullptr; ptr->color = red_node; //新增节点为红节点 if (!header) //若树为空 header为保存的根节点 { header = ptr; header->color = black_node; //根节点颜色为黑色 return true; } pointer cur = header, temp = nullptr; //找到待插入节点的父节点 while (cur != nullptr) { temp = cur; if (v < value(cur)) cur = left(cur); else cur = right(cur); } //temp此时即为待插入节点的父节点 //与祖父节点值相同则不插入 或者 与父节点相同 if ((parent(temp) && value(parent(temp)) == v)||value(temp) == v) { delete ptr; return false; } parent(ptr) = temp; if (value(temp) > v) left(temp) = ptr; else if (value(temp) < v) right(temp) = ptr; balance_tree(ptr); // 插入完成后再调整树的平衡 count++; return true; }

B3. 红黑树平衡的调整

  • 按照前面提到的规则,实现调整
balance_tree
copy
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
template <typename Value> void rb_tree<Value>::balance_tree(pointer ptr) { pointer PP = parent(parent(ptr)); //祖父节点 if (!PP) //若没有祖父节点,说明父节点为根节点,则直接返回 return; if (parent(ptr)->color == red_node) { //伯父节点存在 且都为红色 if (PP->left != nullptr && PP->right != nullptr && PP->left->color == red_node && PP->right->color == red_node) { //即插入四节点情况,只需更改颜色即可 PP->color = red_node; PP->left->color = black_node; PP->right->color = black_node; //若PP为根节点 if (header == PP) PP->color = black_node; //祖父与祖祖父都为红色 继续调整 else if (parent(PP) != nullptr && parent(PP)->color == red_node) balance_tree2(PP); } //伯父节点不存在 或者为黑色时 //左右外侧插入时,只需要左右旋一次即可 注意颜色要更改 else if ((left(parent(ptr)) == ptr && PP->left == parent(ptr)) || (right(parent(ptr)) == ptr && PP->right == parent(ptr))) { PP->color = red_node; parent(ptr)->color = black_node; if (left(parent(ptr)) == ptr) rightRatote(parent(ptr)); else leftRatote(parent(ptr)); } //内侧插入 需要旋转两次。 第一次旋转完后就成上面的外侧插入了 else { ptr->color = black_node; PP->color = red_node; if (left(parent(ptr)) == ptr) { rightRatote(ptr); leftRatote(ptr); } else { leftRatote(ptr); rightRatote(ptr); } } } }

C. 红黑树节点的删除

红黑树节点的删除

  • 对于节点值的删除,一般是找到前驱节点或后继节点,交换其值,再删除前驱节点或后继节点。最后再平衡该树。
  • 对于平衡树来说,前驱节点或后继节点必定是叶子节点或叶子节点的父节点,在倒数一二层,且最多只有一个孩子
  • 一般删除有如下情况
    • 当删除节点为3,4节点时可以通过内部自行解决。
    • 当删除节点为2节点时,需要父节点和兄弟节点来解决。
  • 红黑树节点删除规则如下
    • 找到待删除值的前驱或后继节点,交换值,再删除前驱或后继节点T。
    • 当T为红色时(三四节点情况存在,且必然没有孩子),则直接删除。因为直接删除不影响黑色平衡。
      • 若红色前驱或后继节点T有孩子,则该左右子树不可能平衡。
    • 当T为黑色无孩子(二节点情况)时,需要调整父节点与兄弟节点。
      • 兄弟节点是红色,父节点变红,兄弟节点变黑,再对父节点左旋或右旋。此时T的兄弟节点变为黑色节点了。
      • 若兄弟节点黑色有一个孩子(三节点情况),则父节点到T的位置,兄弟节点需要左旋右旋出一个最小值节点作为父节点。
      • 若兄弟节点黑色有两个孩子,仍然可以父节点到T的位置,兄弟节点出一个最小值节点作为父节点(需要一次右旋,一次左旋)。
        • 或者直接父节点左旋或右旋一次
      • 若兄弟节点孩子,则在兄弟节点变红基础上。
        • 若父节点为红色,父亲变为黑色即可。
        • 若父节点为黑色,则将叔父变成红色。若祖祖父也为黑色需要往上递归改变,直到当前节点为红色或者根节点
    • 当T为黑色有一个孩子(三节点情况)时,孩子颜色设置为黑色,与孩子交换位置后删除即可。父亡子替

C1. 寻找前驱节点

  • 树节点的删除一般是找其前驱节点或者后继节点的来替代,删除的实际上是该前驱节点或者后继节点的内存。
  • 此处用前驱节点来替代,代码如下。
predecessor
copy
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
// 返回值的typename可以指定后面的这个名字是类中的类型成员,而不是数据成员 template <typename Value> typename rb_tree<Value>::pointer rb_tree<Value>::predecessor(pointer cur) { // 返回前驱节点 if (left(cur) == nullptr) return nullptr; cur = left(cur); while (right(cur) != nullptr) { cur = right(cur); } return cur; }

C2. 红黑树节点的删除

  • 先找到要删除的节点,再找到其前驱节点(后继节点也可以),用该节点的值覆盖给要删除的节点。最后删除前驱节点内存即可。
findByValue,deleteValue
copy
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
template <typename Value> typename rb_tree<Value>::pointer rb_tree<Value>::findByValue(value_type v) { pointer cur = header; while (cur != nullptr) { if (value(cur) < v) cur = right(cur); else if (value(cur) > v) cur = left(cur); else break; } return cur; } //可自行优化该部分代码 template <typename Value> bool rb_tree<Value>::deleteValue(value_type v) { pointer cur = findByValue(v); if (!cur) return false; // 需要被删除的前驱节点 pointer del = predecessor(cur); if (!del) //没有前驱节点,删除自身 del = cur; else cur->value_filed = del->value_filed; pointer deal = del; // 红色直接删除,其必然没有孩子,否则左右子树不可能平衡 if (del->color == red_node) { if (left(parent(del)) == del) left(parent(del)) = nullptr; else right(parent(del)) = nullptr; delete del; count--; return true; } while (deal != nullptr && deal != header && deal->color == black_node) { if (!left(deal) && !right(deal)) //黑色无孩子节点 { // 若兄弟节点是红色,让父节点变红,兄弟节点变黑,再对父节点左旋或右旋,使兄弟节点为黑色 if (right(parent(deal))->color == red_node || left(parent(deal))->color == red_node) { parent(deal)->color = red_node; if (right(parent(deal)) != deal) { right(parent(deal))->color = black_node; leftRatote(right(parent(deal))); } else { left(parent(deal))->color = black_node; leftRatote(left(parent(deal))); } break; } pointer bro = right(parent(deal)) == deal ? left(parent(deal)) : right(parent(deal)); // 黑色兄弟节点有两个孩子 直接左旋或右旋一次 if (left(bro) != nullptr && right(bro) != nullptr) { parent(deal)->color = black_node; if (parent(deal)->left == bro) { parent(deal)->right = nullptr; rightRatote(bro); } else { parent(deal)->left = nullptr; leftRatote(bro); } break; } // 黑色兄弟节点无孩子节点 else if (left(bro) == nullptr && right(bro) == nullptr) { bro->color = red_node; if (parent(deal)->color == red_node) { parent(deal)->color = black_node; if (parent(deal)->left == bro) right(parent(deal)) = nullptr; else left(parent(deal)) = nullptr; break; } else { if (parent(bro)->right == deal) parent(deal)->right = nullptr; else parent(deal)->left = nullptr; // 递归往上 deal = parent(bro); } } // 黑色兄弟节点有一个孩子节点 else { if (left(bro) != nullptr && parent(bro)->right == bro) { rightRatote(left(bro)); bro = parent(bro); } else if (right(bro) != nullptr && parent(bro)->left == bro) { leftRatote(right(bro)); bro = parent(bro); } if (parent(bro)->right == bro) { leftRatote(bro); parent(deal)->left = nullptr; } else { rightRatote(bro); parent(deal)->right = nullptr; } break; } } else { //黑色一个孩子,直接换位置后删除即可 if (left(deal) == nullptr) leftRatote(deal->right); else rightRatote(deal->left); parent(deal)->color = black_node; left(parent(deal)) = nullptr; right(parent(deal)) = nullptr; break; } } delete del; count--; return true; }

完整代码

rb_tree.cpp
copy
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
#include <iostream> #include <new> typedef bool clolor_type; const clolor_type red_node = false; //红色为0 const clolor_type black_node = true; //黑色为1 //节点结构 template <typename Value> struct tree_node { typedef tree_node<Value> *link_type; clolor_type color; link_type parent; link_type left; link_type right; Value value_filed; }; template <typename Value> class rb_tree { private: typedef tree_node<Value> node_type; typedef tree_node<Value> *pointer; typedef Value value_type; inline pointer &left(pointer node) { return (pointer &)node->left; } inline pointer &right(pointer node) { return (pointer &)node->right; } inline pointer &parent(pointer node) { return (pointer &)node->parent; } inline value_type &value(pointer node) { return (value_type &)node->value_filed; } void balance_tree(pointer ptr); void leftRatote(pointer node); void rightRatote(pointer node); void freeMemory(pointer cur); //释放cur为根节点的树 pointer predecessor(pointer cur); pointer findByValue(value_type v); public: pointer header; int count = 0; rb_tree() : header(nullptr){}; ~rb_tree(); bool insert_unique(value_type v); bool deleteValue(value_type v); void display(); void display2(); }; // 返回值的typename可以指定后面的这个名字是类中的类型成员,而不是数据成员 template <typename Value> typename rb_tree<Value>::pointer rb_tree<Value>::predecessor(pointer cur) { // 返回前驱节点 if (left(cur) == nullptr) return nullptr; cur = left(cur); while (right(cur) != nullptr) { cur = right(cur); } return cur; } template <typename Value> typename rb_tree<Value>::pointer rb_tree<Value>::findByValue(value_type v) { pointer cur = header; while (cur != nullptr) { if (value(cur) < v) cur = right(cur); else if (value(cur) > v) cur = left(cur); else break; } return cur; } template <typename Value> bool rb_tree<Value>::deleteValue(value_type v) { pointer cur = findByValue(v); if (!cur) return false; // 需要被删除的前驱节点 pointer del = predecessor(cur); if (!del) //没有前驱节点,删除自身 del = cur; else cur->value_filed = del->value_filed; pointer deal = del; // 红色直接删除,其必然没有孩子,否则左右子树不可能平衡 if (del->color == red_node) { if (left(parent(del)) == del) left(parent(del)) = nullptr; else right(parent(del)) = nullptr; delete del; count--; return true; } while (deal != nullptr && deal != header && deal->color == black_node) { if (!left(deal) && !right(deal)) //黑色无孩子节点 { // 若兄弟节点是红色,让父节点变红,兄弟节点变黑,再对父节点左旋或右旋,使兄弟节点为黑色 if (right(parent(deal))->color == red_node || left(parent(deal))->color == red_node) { parent(deal)->color = red_node; if (right(parent(deal)) != deal) { right(parent(deal))->color = black_node; leftRatote(right(parent(deal))); } else { left(parent(deal))->color = black_node; leftRatote(left(parent(deal))); } break; } pointer bro = right(parent(deal)) == deal ? left(parent(deal)) : right(parent(deal)); // 黑色兄弟节点有两个孩子 直接左旋或右旋一次 if (left(bro) != nullptr && right(bro) != nullptr) { parent(deal)->color = black_node; if (parent(deal)->left == bro) { parent(deal)->right = nullptr; rightRatote(bro); } else { parent(deal)->left = nullptr; leftRatote(bro); } break; } // 黑色兄弟节点无孩子节点 else if (left(bro) == nullptr && right(bro) == nullptr) { bro->color = red_node; if (parent(deal)->color == red_node) { parent(deal)->color = black_node; if (parent(deal)->left == bro) right(parent(deal)) = nullptr; else left(parent(deal)) = nullptr; break; } else { if (parent(bro)->right == deal) parent(deal)->right = nullptr; else parent(deal)->left = nullptr; // 递归往上 deal = parent(bro); } } // 黑色兄弟节点有一个孩子节点 else { if (left(bro) != nullptr && parent(bro)->right == bro) { rightRatote(left(bro)); bro = parent(bro); } else if (right(bro) != nullptr && parent(bro)->left == bro) { leftRatote(right(bro)); bro = parent(bro); } if (parent(bro)->right == bro) { leftRatote(bro); parent(deal)->left = nullptr; } else { rightRatote(bro); parent(deal)->right = nullptr; } break; } } else { //黑色一个孩子,直接换位置后删除即可 if (left(deal) == nullptr) leftRatote(deal->right); else rightRatote(deal->left); parent(deal)->color = black_node; left(parent(deal)) = nullptr; right(parent(deal)) = nullptr; break; } } delete del; count--; return true; } template <typename Value> rb_tree<Value>::~rb_tree() { freeMemory(header); } template <typename Value> void rb_tree<Value>::freeMemory(pointer cur) { if (!cur) return; //释放cur为根节点的树 pointer left = cur->left, right = cur->right; delete cur; if (left) freeMemory(left); if (right) freeMemory(right); } /* root root parent node / \ / \ node brother ---> left parent / \ / \ left right right brother */ template <typename value> void rb_tree<value>::rightRatote(pointer node) { if (!node || !parent(node)) //空节点或没有父节点 return; pointer root = parent(parent(node)); //祖父节点 left(parent(node)) = right(node); if (right(node) != nullptr) right(node)->parent = parent(node); parent(parent(node)) = node; right(node) = parent(node); parent(node) = root; if (!root) //若root为空,即parent是根节点 header = node; else if (value(node) <= value(root)) //判断时否是root的左节点 left(root) = node; else right(root) = node; } /* root root node parent / \ / \ parent right <--- brother node / \ / \ brother left left right */ template <typename Value> void rb_tree<Value>::leftRatote(pointer node) { // 注意被旋转的node节点会跑到上面去 if (!node || !parent(node)) //空节点或没有父节点 return; pointer root = parent(parent(node)); right(parent(node)) = left(node); if (left(node) != nullptr) left(node)->parent = parent(node); parent(parent(node)) = node; left(node) = parent(node); parent(node) = root; if (!root) //若root为空,即parent是根节点 header = node; else if (value(node) <= value(root)) left(root) = node; else right(root) = node; } //无重复插入 template <typename Value> bool rb_tree<Value>::insert_unique(value_type v) { pointer ptr = new node_type; //创建一个节点 value(ptr) = v; //初始化该值 left(ptr) = nullptr; right(ptr) = nullptr; parent(ptr) = nullptr; ptr->color = red_node; //新增节点为红节点 if (!header) //若树为空 header为保存的根节点 { header = ptr; header->color = black_node; //根节点颜色为黑色 return true; } pointer cur = header, temp = nullptr; //找到待插入节点的父节点 while (cur != nullptr) { temp = cur; if (v < value(cur)) cur = left(cur); else cur = right(cur); } // temp此时即为待插入节点的父节点 //与祖父节点值相同则不插入 或者 与父节点相同 if ((parent(temp) && value(parent(temp)) == v) || value(temp) == v) { delete ptr; return false; } parent(ptr) = temp; if (value(temp) > v) left(temp) = ptr; else if (value(temp) < v) right(temp) = ptr; balance_tree(ptr); // 插入完成后再调整树的平衡 count++; return true; } template <typename Value> void rb_tree<Value>::balance_tree(pointer ptr) { pointer PP = parent(parent(ptr)); //祖父节点 if (!PP) //若没有祖父节点,说明父节点为根节点,则直接返回 return; if (parent(ptr)->color == red_node) { //伯父节点存在 且都为红色 if (PP->left != nullptr && PP->right != nullptr && PP->left->color == red_node && PP->right->color == red_node) { //即插入四节点情况,只需更改颜色即可 PP->color = red_node; PP->left->color = black_node; PP->right->color = black_node; //若PP为根节点 if (header == PP) PP->color = black_node; //祖父与祖祖父都为红色 继续调整 else if (parent(PP) != nullptr && parent(PP)->color == red_node) balance_tree(PP); } //伯父节点不存在 或者为黑色时 //左右外侧插入时,只需要左右旋一次即可 注意颜色要更改 else if ((left(parent(ptr)) == ptr && PP->left == parent(ptr)) || (right(parent(ptr)) == ptr && PP->right == parent(ptr))) { PP->color = red_node; parent(ptr)->color = black_node; if (left(parent(ptr)) == ptr) rightRatote(parent(ptr)); else leftRatote(parent(ptr)); } //内侧插入 需要旋转两次。 第一次旋转完后就成上面的外侧插入了 else { ptr->color = black_node; PP->color = red_node; if (left(parent(ptr)) == ptr) { rightRatote(ptr); leftRatote(ptr); } else { leftRatote(ptr); rightRatote(ptr); } } } } template <typename Value> void rb_tree<Value>::display() //用循环进行中序遍历 用递归更方便 { if (header == nullptr) return; pointer cur = header; while (cur->left != nullptr) //第一位元素是最左侧元素 { cur = cur->left; } while (cur != nullptr) { std::cout << cur->value_filed << "(" << cur->color << ") "; if (cur->right != nullptr) { //有右节点就往右走 cur = right(cur); while (cur->left != 0) //一直走左边到底 cur = cur->left; } else { pointer y = cur->parent; //若本身是右节点(既大于该值),就一直上溯,直到不为右子节点为止 while (y != nullptr && cur == y->right) { cur = y; y = y->parent; } cur = y; } } std::cout << std::endl; } //用循环实现前序遍历 递归更方便 template <typename Value> void rb_tree<Value>::display2() { if (!header) return; pointer cur = header; while (cur != nullptr) { std::cout << cur->value_filed << "(" << cur->color << ") "; if (cur->left != nullptr) cur = cur->left; else { if (cur->right != nullptr) cur = cur->right; else { pointer y = cur->parent; if (!y) return; //直到兄弟节点不为空 或者 右侧不是自己 while ((cur == y->left && y->right == nullptr) || cur == y->right) { cur = y; y = y->parent; if (y == nullptr) { std::cout << std::endl; return; } } cur = y->right; } } } std::cout << std::endl; } int main() { using namespace std; rb_tree<int> tree; int num = 0; for (int i = 1; i <= 8; i++) tree.insert_unique(i); tree.display2(); tree.deleteValue(6); tree.deleteValue(7); tree.display2(); return 0; }

参考视频: https://www.bilibili.com/video/BV135411h7wJ

本文作者:oniisan

本文链接:https://www.cnblogs.com/oniisan/p/rb_tree.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Oniisan_Rui  阅读(448)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起