基本思想
红黑树是一种特殊的二叉搜索树,它在二叉搜索树的基础上增加了着色和相关限制,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。
红黑树相较AVL是牺牲了严格的高度平衡的条件为代价,它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能。由于它的设计,任何不平衡都会在三次旋转之内解决。(插入需两次旋转,删除需三次)
具体来说,红黑树有以下几个限制条件:
- 每个节点要么是红色,要么是黑色。
- 根节点必须是黑色的。
- 红色节点的孩子必须是黑色的。
- 对于每个节点而言,其到树尾端NULL指针的每条路径都包含相同数目的黑节点。
由限制条件可得出对于某一节点,其左右子树的高度相差不会超过一倍,这也就保证了红黑树O(logn)的效率。
红黑色的查找、插入、删除操作跟二叉搜索树很相似,只不过由于限制条件,在插入、删除节点后,需要调整树以重新符合限制条件。
左旋、右旋
当红黑树的条件被破坏之后,需要调整树以重新满足限制条件。调整的操作分为两类:一是对于节点颜色的改变,二是对于树结构的调整。而调整树的两个基本操作就是左旋与右旋。
插入节点
步骤一:将红黑树当做普通二叉搜索树,插入节点
注意新插入的节点颜色为红色。
步骤二:通过旋转及着色等操作使其重新恢复红黑树条件
(1) 插入节点为根节点(即原来树为空)
直接将该节点涂为黑色即可
(2)插入节点的父节点为黑色节点
无需任何操作,此时仍符合条件
(3)插入节点的父节点为红色节点
①当前节点的父节点是红色,且当前节点的祖父节点的另一个子节点(叔叔节点)也是红色。
把父节点和叔叔节点涂为黑色,把祖父节点涂为红色,接着设祖父节点为“当前节点”,继续进行处理。
②当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的右孩子
将父节点设为“新的当前节点”,并以“新的当前节点”进行左旋。
③当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的左孩子
将父节点涂为黑色,将祖父节点涂为红色,对祖父节点进行右旋。
具体来说就是,情况①把自身处理好了后,把黑锅“嫁祸”给祖父节点进行处理。而情况②就是把自身转为情况③再进行处理。处理起来就好像红色节点逐渐地被传递给了上层,最终需把根节点涂为黑色。
下图为一次调整流程。
删除节点
删除同样是跟普通二叉搜索树一样,只不过删除后要调整树以重新满足限制条件,这里我真的看不懂,写不出来,留个坑吧。
定义
enum Color{RED, BLACK};
template <typename T>
class Node
{
public:
T key;
Color color;
Node* parent;
Node* left;
Node* right;
Node(T k, Color c, Node* p = nullptr, Node* l = nullptr, Node* r = nullptr) :
key(k), color(c), parent(p), left(l), right(r) {}
};
template <typename T>
class RBTree
{
private:
Node<T>* root_;
public:
RBTree();
~RBTree();
Node<T>* Search(T key);
void Insert(T key);
void Remove(T key);
private:
void LeftRotate(Node<T>* head);
void RightRotate(Node<T>* head);
void FixAfterInsert(Node<T>* node);
void FixAfterRemove(Node<T>* node);
void Destory(Node<T>* &head);
};
代码
template <typename T>
RBTree<T>::RBTree() : root_(nullptr) {}
template <typename T>
RBTree<T>::~RBTree()
{
Destory(root_);
}
template <typename T>
Node<T>* RBTree<T>::Search(T key)
{
Node<T>* cur = root_;
while (cur && cur->key != key)
{
if (key < cur->key)
cur = cur->left;
else
cur = cur->right;
}
return cur;
}
// 将head节点左旋
template <typename T>
void RBTree<T>::LeftRotate(Node<T>* head)
{
Node<T>* tmp = head->right;
head->right = tmp->left;
if (tmp->left)
tmp->left->parent = head;
tmp->parent = head->parent;
if (head->parent)
{
if (head->parent->left == head)
head->parent->left = tmp;
else
head->parent->right = tmp;
}
else
{
root_ = tmp;
}
head->parent = tmp;
tmp->left = head;
}
// 将head节点右旋
template <typename T>
void RBTree<T>::RightRotate(Node<T>* head)
{
Node<T>* tmp = head->left;
head->left = tmp->right;
if (tmp->right)
tmp->right->parent = head;
tmp->parent = head->parent;
if (head->parent)
{
if (head->parent->left == head)
head->parent->left = tmp;
else
head->parent->right = tmp;
}
else
{
root_ = tmp;
}
head->parent = tmp;
tmp->right = head;
}
template <typename T>
void RBTree<T>::FixAfterInsert(Node<T>* node)
{
Node<T>* parent;
Node<T>* gparent;
// 父节点存在,且为红色
while ((parent = node->parent) && parent->color == RED)
{
gparent = parent->parent;
// 父节点为祖父节点的左孩子
if (parent == gparent->left)
{
// 情况1:叔叔节点也为红色
Node<T>* uncle = gparent->right;
if (uncle && uncle->color == RED)
{
parent->color = BLACK;
uncle->color = BLACK;
gparent->color = RED;
node = gparent; // 往上层继续处理
continue;
}
// 情况2:叔叔节点为黑色,且当前节点是右孩子
if (parent->right == node)
{
LeftRotate(parent);
Node<T>* tmp = parent;
parent = node;
node = tmp;
}
// 情况3:叔叔节点为黑色,且当前节点为左孩子
parent->color = BLACK;
gparent->color = RED;
RightRotate(gparent);
}
else
{
Node<T>* uncle = gparent->left;
if (uncle && uncle->color == RED)
{
parent->color = BLACK;
uncle->color = BLACK;
gparent->color = RED;
node = gparent;
continue;
}
if (parent->left == node)
{
RightRotate(parent);
Node<T>* tmp = parent;
parent = node;
node = tmp;
}
parent->color = BLACK;
gparent->color = RED;
LeftRotate(gparent);
}
}
root_->color = BLACK;
}
template <typename T>
void RBTree<T>::Insert(T key)
{
Node<T>* cur = root_;
Node<T>* pre = nullptr;
// 找到插入位置
while (cur)
{
pre = cur;
if (key == cur->key)
return;
else if (key < cur->key)
cur = cur->left;
else
cur = cur->right;
}
Node<T>* new_node = new Node<T>(key, RED);
new_node->parent = pre;
// 插入为根节点
if (pre == nullptr)
root_ = new_node;
// 插入为左孩子
else if (key < pre->key)
pre->left = new_node;
// 插入为右孩子
else
pre->right = new_node;
FixAfterInsert(new_node);
}
template <typename T>
void RBTree<T>::FixAfterRemove(Node<T>* node)
{
Node<T>* brother;
Node<T>* parent = node->parent;
while ((!node || node->color == BLACK) && node != root_)
{
if (parent->left == node)
{
// case1
brother = parent->right;
if (brother->color == RED)
{
brother->color = BLACK;
parent->color = RED;
LeftRotate(parent);
brother = parent->right;
}
// case2
if ((!brother->left || brother->left->color == BLACK) &&
(!brother->right || brother->right->color == BLACK))
{
brother->color = RED;
node = parent;
parent = node->parent;
}
else
{
// case3
if (!brother->right || brother->right->color == BLACK)
{
brother->left->color = BLACK;
brother->color = RED;
RightRotate(brother);
brother = parent->right;
}
// case 4
brother->color = parent->color;
parent->color = BLACK;
brother->right->color = BLACK;
LeftRotate(parent);
node = root_;
break;
}
}
else
{
// case1
brother = parent->left;
if (brother->color == RED)
{
brother->color = BLACK;
parent->color = RED;
RightRotate(parent);
brother = parent->left;
}
// case2
if ((!brother->left || brother->left->color == BLACK) &&
(!brother->right || brother->right->color == BLACK))
{
brother->color = RED;
node = parent;
parent = node->parent;
}
else
{
// case3
if (!brother->left || brother->left->color == BLACK)
{
brother->right->color = BLACK;
brother->color = RED;
LeftRotate(brother);
brother = parent->left;
}
// case 4
brother->color = parent->color;
parent->color = BLACK;
brother->left->color = BLACK;
RightRotate(parent);
node = root_;
break;
}
}
}
if (node)
node->color = BLACK;
}
template <typename T>
void RBTree<T>::Remove(T key)
{
Node<T>* r = Search(key);
if (r == nullptr)
return;
// 左右孩子皆非空,转为至少有一空情况
if (r->left != nullptr && r->right != nullptr)
{
Node<T>* cur = r->right;
while (cur->left)
cur = cur->left;
r->key = cur->key;
r = cur;
}
Node<T>* child = r->left != nullptr ? r->left : r->right;
Node<T>* parent = r->parent;
if (child) // 左右子树有一为空
{
child->parent = parent;
if (parent == nullptr)
root_ = child;
else if (parent->left == r)
parent->left = child;
else
parent->right = child;
if (r->color == BLACK)
FixAfterRemove(child);
}
else if (parent == nullptr) // 左右子树皆空,且该点为根节点
{
root_ = nullptr;
}
else // 左右子树皆空
{
if (r->color == BLACK)
FixAfterRemove(r);
if (r->parent != nullptr)
{
if (parent->left == r)
parent->left = nullptr;
else
parent->right = nullptr;
}
}
delete r;
}
template <typename T>
void RBTree<T>::Destory(Node<T>* &head)
{
if (head == nullptr)
return;
if (head->left)
Destroy(head->left);
if (head->right)
Destroy(head->right);
delete head;
head = nullptr;
}