红黑树(Red-Black Tree)是一种自平衡的二叉搜索树,通过颜色约束 + 旋转 + 变色 来保证树的高度始终为 O(logn)。插入和删除后可能破坏红黑性质,需进行调整(fixup)。
红黑树要满足以下几个条件:
- 根节点为黑色
- 红色节点的孩子必须是黑色节点
- 任意一条路径上的黑色节点数量相等
- 最长路径上的节点数量不超过最短路径节点数量的两倍
接下来就来详细介绍红黑树旋转 + 变色的几种情况。
一、叔节点 u 是 红色
cpp
g(B) g(R)
/ \ / \
p(R) u(R) → p(B) u(B)
/ /
z(R) z(R)
这时只需要将grandpa变为红色,parent和uncle介蒂安变为黑色。由于grandpa节点变成红色,此时需要继续向上检查。
二、叔节点为黑色或为空
在这种情况下就会变得复杂得多,涉及到旋转和变色。
2.1、RR型
cpp
g(B) p(B)
/ \ / \
u(B) p(R) → g(R) z(R)
\ /
z(R) u(B)
叔节点为黑色或为空时,在RR型中需要将grandpa节点进行左旋,并且将parent节点变成黑色grandpa节点变成红色。注意这里由于parent节点已经变成黑色,不需要再向上进行调整。
2.2、RL型
cpp
g(B) g(B) z(B)
/ \ / \ / \
u(B) p(R) → u(B) z(R) → g(R) p(R)
/ \ /
z(R) p(R) u(B)
叔节点为黑色或为空时,在RL型中需要先将parent节点进行右旋转化为RR型,再对grandpa节点进行左旋。同时z节点变成黑色,grandpa节点变成红色。
2.3、LL型
cpp
g(B) p(B)
/ \ / \
p(R) u(B) → z(R) g(R)
/ \
z(R) u(B)
叔节点为黑色或为空时,在LL型中需要将grandpa节点进行右旋,并且将parent节点变成黑色grandpa节点变成红色。注意这里由于parent节点已经变成黑色,不需要再向上进行调整。
2.4、LR型
cpp
g(B) g(B) z(B)
/ \ / \ / \
p(R) u(B) → z(R) u(B) → p(R) g(R)
\ / \
z(R) p(R) u(B)
叔节点为黑色或为空时,在LR型中需要先将parent节点进行左旋转化为LL型,再对grandpa节点进行右旋旋。同时z节点变成黑色,grandpa节点变成红色。
三、旋转与变色总结
| 况 | 叔叔颜色 | 当前节点位置 | 操作 |
|---|---|---|---|
| Case 1 | 红色 | 任意 | 变色(p, u → 黑;g → 红),继续向上 |
| Case 2 | 黑色 | 外侧(LL/RR) | 单旋 + 变色(p 与 g 交换颜色) |
| Case 3 | 黑色 | 内侧(LR/RL) | 双旋 + 变色(先转外侧,再单旋) |
四、代码实现
cpp
#include<iostream>
using namespace std;
enum color
{
RED, BLACK
};
template<class T>
class RBNode {
public:
RBNode(const T& val=T()):
date(val),
_parent(nullptr),
_left(nullptr),
_right(nullptr),
col(RED)
{
}
T date;
RBNode<T>* _parent;
RBNode<T>* _left;
RBNode<T>* _right;
color col;
};
template<class T>
class RBTree {
public:
typedef RBNode<T> Node;
RBTree():_root(nullptr){}
void insert(const T& x)
{
//插入节点
Node* cur = _root, * parent = nullptr, * nn = new Node(x);
while (cur)
{
parent = cur;
if (x < cur->date) { cur = cur->_left; }
else
{
cur = cur->_right;
}
}
if (parent == nullptr)//如果是空树
{
_root = nn;
}
else
{
nn->_parent = parent;
if (nn->date < parent->date) parent->_left = nn;
else
{
parent->_right = nn;
}
cur = nn;
}
//修善红黑树
while (parent && parent->col == cur->col && cur->col == RED)
{
Node* uncle;
Node* grandpa = parent->_parent;
if (grandpa)
{
if (parent == grandpa->_left)
{
uncle = grandpa->_right;
if (uncle && uncle->col == RED)//uncle是红色
{
grandpa->col = RED;
parent->col = uncle->col = BLACK;
cur = grandpa;
parent = cur->_parent;
if (parent) grandpa = parent->_parent;
else
{
grandpa = nullptr;
}
}
else
{
if (cur == parent->_left)
{
rotateRight(grandpa);
parent->col = BLACK;
grandpa->col = RED;
}
else
{
rotateLeft(parent);
rotateRight(grandpa);
cur->col = BLACK;
grandpa->col = RED;
}
break;
}
}
else
{
uncle = grandpa->_left;
if (uncle && uncle->col == RED)//uncle是红色
{
grandpa->col = RED;
grandpa->col = RED;
parent->col = uncle->col = BLACK;
cur = grandpa;
parent = cur->_parent;
if (parent) grandpa = parent->_parent;
else
{
grandpa = nullptr;
}
}
else
{
if (cur == parent->_right)
{
rotateLeft(grandpa);
parent->col = BLACK;
grandpa->col = RED;
}
else
{
rotateRight(parent);
rotateLeft(grandpa);
cur->col = BLACK;
grandpa->col = RED;
}
break;
}
}
}
}
_root->col = BLACK;//根节点常置为black
}
void rotateLeft(Node* node)
{
Node* parent = node->_parent, * rc = node->_right, * rlc = node->_right->_left;
node->_right = rlc;
if (rlc) rlc->_parent = node;
rc->_left =node;
node->_parent = rc;
if (parent == nullptr)
{
rc->_parent = nullptr;
_root = rc;
}
else
{
rc->_parent = parent;
if (parent->_left == node)
{
parent->_left = rc;
}
else
{
parent->_right = rc;
}
}
}
void rotateRight(Node* node)
{
// node
// lc
// lrc
Node* parent = node->_parent, * lc = node->_left, * lrc = node->_left->_right;
node->_left = lrc;
if (lrc) lrc->_parent = node;
lc->_right = node;
node->_parent = lc;
if (parent == nullptr)
{
lc->_parent = nullptr;
_root = lc;
}
else
{
if (parent->_left == node)
{
parent->_left = lc;
lc->_parent = parent;
}
else
{
parent->_right = lc;
lc->_parent = parent;
}
}
}
void InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
InOrder(root->_left);
//cout << root->_date << " ";
cout << root->_date <<"##";
InOrder(root->_right);
}
void PreOrder(Node* root)
{
if (root == nullptr)
{
return;
}
cout << root->_date << "##";
PreOrder(root->_left);
PreOrder(root->_right);
}
Node* getRoot()
{
return _root;
}
bool isRBTree()
{
return isRBTree(_root, 0);
}
private:
bool isRBTree(Node* node, int cb)
{
if (node == nullptr)
{
if (cb == countBlack()) return true;
else
{
return false;
}
}
if (node->col == RED && node->_parent->col == RED)
{
return false;
}
int i = 0;
if (node->col == BLACK) i++;
return isRBTree(node->_left, cb + i) && isRBTree(node->_right, cb + i);
}
int countBlack()
{
int count = 0;
Node* tmp = _root;
while (tmp)
{
if (tmp->col == BLACK)
{
count++;
}
tmp = tmp->_right;
}
return count;
}
Node* _root;
};