1.红黑树是什么?
红黑树首先是一棵自平衡二叉查找树。它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但 对之进行平衡的代价较低, 其平均统计性能要强于 AVL 。
它具有以下的特性:
- 节点颜色非红即黑
- 根节点黑色
- 叶子节点黑色(空节点)
- 红色节点不能连续
- 节点到空节点的任意路径黑色节点个数相同
2.原理
2.1、左旋和右旋
如下图所示,设失衡节点为S,父节点为P,父节点为G,P兄弟节点为B。
1)满足特性(4),将P涂黑;此时左侧黑色长度加一。
2)满足特性(5),将G涂红;此时右侧黑色长度减一。
3)满足特性(5),以P为中心向右旋转;;此时红黑树平衡。
2.1、添加节点
首先,按照二叉树的原理,插入新节点。
设失衡节点为S,父节点为P,祖父节点为G,P兄弟节点为B。
则插入的基本流程如下:
1)判断是否根节点
2)判断父节点颜色
3)判断父节点属于祖父节点的哪一个分支
4)判断失衡节点属于祖父节点的哪一个分支
2.2、删除节点
首先,按照二叉树的原理,删除指定节点S。
设失衡节点为S(S = P->L),父节点为P,兄弟节点为B。
则插入的基本流程如下:
1)判断是否存在左节点
2)判断是否存在右节点
3)判断节点颜色
4)判断兄弟节点的右节点颜色
5)判断兄弟节点的左节点颜色
6)判断父节点颜色
3.示例
简单实现
enum RBColor { RED, BLACK };
template <class K, class V>
class RBTree {
private:
class RBNode {
private:
friend class RBTree;
K key;
V val;
RBColor color;
RBNode *l;
RBNode *r;
RBNode *p;
public:
RBNode(RBNode *parent, K key, V data) : p(parent), key(key), val(data) {
this->l = this->r = nullptr;
if (this->p == nullptr)
this->color = BLACK; // 2)
else
this->color = RED; // 5)
}
~RBNode() { ; }
};
void DelNode(RBNode *node) {
if (node != nullptr) {
DelNode(node->l);
DelNode(node->r);
delete node;
}
}
bool isRed(RBNode *node) {
if (node == nullptr) return false;
if (node->color == RED)
return true;
else
return false;
}
RBNode *ReColor(RBNode *node) {
if (node != root) node->color = RED;
node->l->color = node->r->color = BLACK;
return node;
}
RBNode *ReColor(RBNode *node, bool left) {
node->color = RED;
if (left)
node->l->color = BLACK;
else
node->r->color = BLACK;
return node;
}
RBNode *LL(RBNode *node) {
RBNode *_new = node->l;
// 更新子节点信息
node->l = _new->r;
if (node->l != nullptr) node->l->p = node;
_new->r = node;
// 更新父节点信息
_new->p = node->p;
node->p = _new;
return _new;
}
RBNode *RR(RBNode *node) {
RBNode *_new = node->r;
node->r = _new->l;
if (node->r != nullptr) node->r->p = node;
_new->l = node;
_new->p = node->p;
node->p = _new;
return _new;
}
/*
* 红黑树插入存在3种情形:(1,2不需要特殊处理)
* 1) 插入根节点
* 2) 父节点黑色
* 3) 父节点/叔叔红色, 祖父节点黑色
* 3)递归后, 出现以下情形:
* 3-1) 父节点黑色, 同2)
* 3-2) 父节点/叔叔红色, 祖父节点黑色, 同3)
* 3-3) 父节点红色, 叔叔节点/祖父节点黑色
*/
RBNode *add(RBNode *parent, RBNode *node, K key, V data, int &weight) {
if (node == nullptr) {
weight = 3;
return new RBNode(parent, key, data);
}
if (key < node->key) {
node->l = add(node, node->l, key, data, weight);
if (weight) {
weight = (weight == 3) ? -3 : weight;
weight = weight - 1;
}
} else if (key > node->key) {
node->r = add(node, node->r, key, data, weight);
weight = (weight == 0) ? weight : weight + 1;
}
return rebalance(node, weight);
}
RBNode *get(RBNode *node, K key) {
if (node == nullptr) return nullptr;
if (node->key == key)
return node;
else if (key < node->key)
return get(node->l, key);
else
return get(node->r, key);
}
RBNode *Max(RBNode *node) {
while (node->r != nullptr) {
node = node->r;
}
return node;
}
RBNode *rebalance(RBNode *node, int &weight) {
switch (weight) {
case -5: // 此时左子树红色长度加1
case 3:
if ((node->l->l != nullptr && isRed(node->l->l)) ||
(node->l->r != nullptr && isRed(node->l->r))) {
if (isRed(node->l)) {
if (isRed(node->r)) // 插入情形3-2)
{
node = ReColor(node);
weight = 3;
break;
} else { // 插入情形3-3)
if (weight == 3) node->l = RR(node->l); // 转换为ll情形
node = ReColor(node, true); // 解决特性4)
node = LL(node); // 解决特性5)
}
}
}
weight = 0;
break;
case 5: // 此时右子树红色长度加1
case -3:
if ((node->r->r != nullptr && isRed(node->r->r)) ||
(node->r->l != nullptr && isRed(node->r->l))) {
if (isRed(node->r)) {
if (isRed(node->l)) // 情形3-2)
{
node = ReColor(node);
weight = 3;
break;
} else { // 情形3-3)
if (weight == -3) node->r = LL(node->r); // 转换为rr情形
node = ReColor(node, false); // 解决特性4)
node = RR(node); // 解决特性5)
}
}
}
weight = 0;
break;
// 此时左子树黑色长度减1
case -2:
/*
* 设当前节点的左右子树的黑色节点长度L=R=n
* 此时,左子树L=n-1,R=n
* 为使左右平衡,存在2个方案:
* 1)通过旋转将右子黑色节点转移到左子树,同时将一个红色节点涂黑。
* 2)将右子树的一个黑色节点涂红,向上递归。
*/
if (node->r->r != nullptr && isRed(node->r->r)) { // 方案1)
node = RR(node);
// 交换父节点和右节点颜色
node->color = node->l->color;
node->l->color = BLACK;
// 涂黑红色颜色
node->r->color = BLACK;
// 平衡常数置零
weight = 0;
} else if (node->r->l != nullptr && isRed(node->r->l)) { // 方案1)
node->r = LL(node->r);
node = RR(node);
// 交换父节点和右节点颜色
node->color = node->l->color;
node->l->color = BLACK;
// 涂黑红色颜色
node->r->color = BLACK;
// 平衡常数置零
weight = 0;
} else if (isRed(node->r)) {
node = RR(node);
// 交换父节点和右节点颜色
node->color = BLACK;
node->l->color = RED;
node->l = rebalance(node->l, weight);
} else if (isRed(node->r) == false) { // 右节点和右子节点均为黑色
node->r->color = RED;
if (isRed(node)) { // 父节点红色
node->color = BLACK;
weight = 0;
} else { // 父节点黑色 方案2)
weight = -1;
}
}
break;
case 2: // 右子树黑色长度减1
if (node->l->l != nullptr && isRed(node->l->l)) { // 方案1)
node = LL(node);
// 交换父节点和右节点颜色
node->color = node->r->color;
node->r->color = BLACK;
// 涂黑红色颜色
node->l->color = BLACK;
// 平衡常数置零
weight = 0;
} else if (node->l->r != nullptr && isRed(node->l->r)) { // 方案1)
node->l = RR(node->l);
node = LL(node);
// 交换父节点和右节点颜色
node->color = node->r->color;
node->r->color = BLACK;
// 涂黑红色颜色
node->l->color = BLACK;
// 平衡常数置零
weight = 0;
} else if (isRed(node->l)) {
node = LL(node);
// 交换父节点和右节点颜色
node->color = BLACK;
node->r->color = RED;
node->r = rebalance(node->r, weight);
} else if (isRed(node->l) == false) { // 节点和子节点均为黑色
node->l->color = RED;
if (isRed(node)) { // 父节点红色
node->color = BLACK;
weight = 0;
} else { // 父节点黑色 方案2)
weight = -1;
}
}
break;
default:
break;
}
return node;
}
/*
* 红黑树插入存在4种情形:
* 1) 叶子节点
* 2) 存在左子树
* 2-1) 删除节点红-子节点黑, 不符合特性5)
* 2-2) 删除节点黑-子节点红
* 3) 存在右子树
* 3-1) 删除节点红-子节点黑, 不符合特性5)
* 3-2) 删除节点黑-子节点红
* 4)存在左右子树, 用前驱节点(K,V)替换删除节点,转变为删除前驱节点。1) 2)
*/
RBNode *remove(RBNode *node, K key, int &weight) {
if (node == nullptr) return nullptr;
RBNode *_new = nullptr;
if (key < node->key) {
node->l = remove(node->l, key, weight);
_new = node;
weight = (weight == -1) ? -2 : 0; //
} else if (key > node->key) {
node->r = remove(node->r, key, weight);
weight = (weight == -1) ? 2 : 0; //
_new = node;
} else {
if (node->l == nullptr) {
_new = node->r;
if (_new != nullptr) { // 3-2)
_new->p = node->p;
_new->color = BLACK;
} else if (node->color == BLACK) {
weight = -1; // 1) 删除节点为黑
} else {
; // 1) 当前节点为红
}
} else if (node->r == nullptr) {
_new = node->l; // 2-2)
_new->p = node->p;
_new->color = BLACK;
} else { // 4)
_new = Max(node->l); // 在左子树寻找前驱节点
_new->l = remove(node->l, _new->key, weight);
_new->p = node->p;
_new->r = node->r;
_new->color = node->color;
if(_new->l != nullptr)
_new->l->p = _new;
if(_new->r != nullptr)
_new->r->p = _new;
weight = (weight == -1) ? -2 : 0;
}
}
return rebalance(_new, weight);
}
RBNode *root;
#ifdef _DEBUG
int Check(RBNode *node) {
if (node == nullptr)
return 1;
else {
if (isRed(node) && isRed(node->p)) return -1;
if (node->l != nullptr && node != node->l->p) return -1;
if (node->r != nullptr && node != node->r->p) return -1;
int left = Check(node->l);
int right = Check(node->r);
if (left == -1 || right == -1 || left != right) return -1;
if (node->color == RED)
return left;
else
return left + 1;
}
}
#endif
public:
RBTree() { root = nullptr; }
~RBTree() { DelNode(root); }
void add(K key, V data) {
RBNode *node = get(root, key);
if (node != nullptr) return;
int weight = 0;
root = add(root, root, key, data, weight);
}
V get(int key) {
RBNode *node = get(root, key);
if (node != nullptr) return node->val;
return nullptr;
}
#ifdef _DEBUG
int Check() { return Check(root); }
#endif
V remove(int key) {
RBNode *node = get(root, key);
if (node == nullptr) return 0;
V val = node->val;
int weight = 0;
root = remove(root, key, weight);
delete node;
return val;
}
};