红黑树是一种数据结构,C++的set, map,和linux的内存管理都是用红黑树实现的。红黑树也是一棵二叉查找树,但是因为其自身结构的特点,其本身非常均衡。时间复杂度为O(logn)。因为在每次插入一个节点或者删除一个节点,红黑树都要对此进行调整。
下面先介绍红黑树的特点,红黑树具有以下几个特征:
1.每个节点不是红色就是黑色的;
2.根节点总是黑色的;
3.每个叶节点是黑色的(nil)
4.如果节点是红色的,则它的子节点必须是黑色的(反之不一定);
5.从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)。
红黑树主要通过三种方式修正树的平衡,变色,左旋和右旋。
左旋和右旋的代码如下:
左旋:
void leftRotate(RBNode *x) {
RBNode *y = x->right;
x->right = y->left;
if (y->left) {
y->left->parent = x;
}
y->parent = x->parent;
if (x->parent == nullptr) {
root = y;
}
else if (x == x->parent->left) {
x->parent->left = y;
}
else {
x->parent->right = y;
}
y->left = x;
x->parent = y;
}
右旋:
void rightRoate(RBNode *y) {
RBNode *x = y->left;
y->left = x->right;
if (x->right) {
x->right->parent = y;
}
x->parent = y->parent;
if (y->parent == nullptr) {
root = x;
}
else if (y == y->parent->left) {
y->parent->left = x;
}
else {
y->parent->right = x;
}
x->right = y;
y->parent = x;
}
变色主要体现在插入和删除节点部分。插入和删除部分比较复杂,我在看书的过程中做了一些笔记。大家可以参考一下:
插入节点平衡调整如下:
删除节点的调整如下:
这两部分的代码如下:
void insertFixUp(RBNode *z) {
RBNode *par, *gParent;
while(z->parent != NULL && z->parent->color == RED) {
par = z->parent;
gParent = par->parent;
if (par == gParent->left) {
RBNode *uncle = gParent->right;
if (uncle->color == RED) {
par->color = BLACK;
uncle->color = BLACK;
gParent->color = RED;
z = gParent;
continue;
}
else if (z == par->right){
leftRotate(par);
RBNode *tmp = par;
par = z;
z = tmp;
}
par->color = BLACK;
gParent->color = RED;
rightRoate(gParent);
}
else {
RBNode *uncle = gParent->left;
if (uncle->color == RED) {
par->color = BLACK;
uncle->color = BLACK;
gParent->color = RED;
z = gParent;
continue;
}
else if (z == par->left) {
rightRoate(par);
RBNode* tmp = par;
par = z;
z = par;
}
par->color = BLACK;
gParent->color = RED;
leftRotate(gParent);
}
root->color = BLACK;
}
}
//插入一个节点
void insertNode(RBNode *z) {
RBNode *y = nullptr;
RBNode *x = root;
while(x) {
if (z->val < x->val) {
x = x->left;
}
else {
x = x->right;
}
}
z->parent = y;
if (y == nullptr) {
z = root;
}
else if (z->val < y->val) {
y->left = z;
}
else {
y->right = z;
}
z->setColor(RED);
insertFixUp(z);
}
void deleteFixUp(RBNode *x) {
RBNode *other, *par;
while ((x == nullptr || x->color == BLACK) && x != root) {
par = x->parent;
if (x == par->left) {
other = par->right;
if (other->color == RED) {
other->color = BLACK;
par->color = RED;
leftRotate(par);
other = par->right;
}
if ((other->left == nullptr || other->left->color == BLACK) && (other->right == nullptr && other->right->color == BLACK)) {
other->color = RED;
x = par;
}
else if (other->right == nullptr || other->right->color == BLACK) {
other->left->color = BLACK;
other->color = RED;
rightRoate(other);
other = par->right;
}
other->color = par->color;
par->color = BLACK;
other->right->color = BLACK;
leftRotate(par);
x = root;
break;
}
else {
other = par->left;
if (other->color = RED) {
other->color = BLACK;
par->color = RED;
rightRoate(par);
other = par->left;
}
if ((other->left == nullptr || other->left->color == BLACK) && (other->right == nullptr && other->right->color == BLACK)) {
other->color = RED;
x = par;
}
else if (other->left == nullptr || other->left->color == BLACK) {
other->right->color = BLACK;
other->color = RED;
leftRotate(other);
other = par->left;
}
other->color = par->color;
par->color = BLACK;
other->left->color = BLACK;
rightRoate(par);
x = root;
break;
}
}
if (x) {
x->color = BLACK;
}
}
//删除一个节点
void deleteNode(RBNode *z) {
RBNode *successor;
if (!z->left || !z->right) {
successor = z;
}
else {
successor = z->right;
while (successor->left != nullptr) {
successor = successor->left;
}
}
RBNode *nexts;
if (successor->left) {
nexts = successor->left;
}
else {
nexts = successor->right;
}
if (successor->parent == nullptr) {
root = nexts;
}
else if (successor == successor->parent->left) {
successor->parent->left = nexts;
}
else {
successor->parent->right = nexts;
}
if (successor != z) {
z->val = successor->val;
}
if (successor->color == BLACK) {
deleteFixUp(successor);
}
}
红黑树的结构如下:
const int RED = 1;
const int BLACK = 0;
class RBNode {
public:
int val;
int color;
RBNode *left;
RBNode *right;
RBNode *parent;
RBNode() {
val = -1;
color = -1;
left = nullptr;
right = nullptr;
parent = nullptr;
}
void setVal(int val) {
val = val;
}
void setColor(int color) {
color = color;
}
};