因为红黑树首先是二叉所搜树,所以有了二叉搜索树的实现,我们就可以重用部分二叉搜索树的类的接口了,rbt.h:
#ifndef __RBT_H__
#define __RBT_H__
#include "bst.h"
template <typename T>
class CRedBlackTree : public CBinarySortTree<T>
{
public:
CRedBlackTree();
~CRedBlackTree() {}
virtual CBinaryTreeNode<T>* Insert(const T& key);
virtual void Delete(CBinaryTreeNode<T>** del);
virtual void InorderWalk() const;
private:
void InsertFixup(CBinaryTreeNode<T>* node);
void DeleteFixup(CBinaryTreeNode<T>* node);
void LeftRotate(CBinaryTreeNode<T>* node);
void RightRotate(CBinaryTreeNode<T>* node);
void InorderWalk(const CBinaryTreeNode<T>* node) const;
};
template <typename T>
CRedBlackTree<T>::CRedBlackTree() : CBinarySortTree<T>()
{
}
template <typename T>
CBinaryTreeNode<T>* CRedBlackTree<T>::Insert(const T& key)
{
CBinaryTreeNode<T>* add = CBinarySortTree<T>::Insert(key);
InsertFixup(add);
return add;
}
template <typename T>
void CRedBlackTree<T>::Delete(CBinaryTreeNode<T>** del)
{
CBinaryTreeNode<T>* temp = &CBinarySortTree<T>::sentinel;
CBinaryTreeNode<T>* node = *del;
CBinaryTreeNode<T>* fixup = &CBinarySortTree<T>::sentinel;
enum CBinaryTreeNode<T>::eColor original_color = (*del)->color;
if (node->left == &CBinarySortTree<T>::sentinel && node->right == &CBinarySortTree<T>::sentinel) {
CBinaryTreeNode<T>* parent = node->parent;
if (parent != &CBinarySortTree<T>::sentinel) {
if (parent->left == node) {
parent->left = &CBinarySortTree<T>::sentinel;
fixup = parent->left;
} else {
parent->right = &CBinarySortTree<T>::sentinel;
fixup = parent->right;
}
fixup->parent = parent; // 'cause sentinel's parent points to itself
} else {
*del = &CBinarySortTree<T>::sentinel;
this->root = &CBinarySortTree<T>::sentinel;
}
temp = node;
} else if (node->left == &CBinarySortTree<T>::sentinel && node->right != &CBinarySortTree<T>::sentinel) {
fixup = node->right;
temp = this->Transplant(node, node->right);
} else if (node->left != &CBinarySortTree<T>::sentinel && node->right == &CBinarySortTree<T>::sentinel) {
fixup = node->left;
temp = this->Transplant(node, node->left);
} else {
CBinaryTreeNode<T>* successor = this->SearchMinOnRightChild(node->right);
original_color = successor->color;
fixup = successor->right;
if (successor->parent != node) {
this->Transplant(successor, successor->right);
successor->right = node->right;
successor->right->parent = successor;
} else
fixup->parent = successor; // 'cause sentinel's parent points to itself
temp = this->Transplant(node, successor);
successor->left = node->left;
successor->left->parent = successor;
successor->color = (*del)->color; // remain the original color
}
if (original_color == CBinaryTreeNode<T>::BLACK && this->root != &CBinarySortTree<T>::sentinel)
DeleteFixup(fixup);
delete temp;
}
template <typename T>
void CRedBlackTree<T>::InorderWalk() const
{
InorderWalk(this->root);
}
template <typename T>
void CRedBlackTree<T>::InorderWalk(const CBinaryTreeNode<T>* node) const
{
const CBinaryTreeNode<T>* p = node;
if (p != &CBinarySortTree<T>::sentinel) {
InorderWalk(p->left);
cout << p->key << ((p->color == CBinaryTreeNode<T>::RED) ? " RED" : " BLACK") << endl;
InorderWalk(p->right);
}
}
template <typename T>
void CRedBlackTree<T>::InsertFixup(CBinaryTreeNode<T>* node)
{
CBinaryTreeNode<T>* y = &CBinarySortTree<T>::sentinel;
while (node->parent != &CBinarySortTree<T>::sentinel && node->parent->color == CBinaryTreeNode<T>::RED) {
if (node->parent == node->parent->parent->left) {
y = node->parent->parent->right; // uncle node
if (y->color == CBinaryTreeNode<T>::RED) {
node->parent->color = CBinaryTreeNode<T>::BLACK;
y->color = CBinaryTreeNode<T>::BLACK;
node->parent->parent->color = CBinaryTreeNode<T>::RED;
node = node->parent->parent;
} else {
if (node == node->parent->right) {
node = node->parent;
LeftRotate(node);
}
node->parent->color = CBinaryTreeNode<T>::BLACK;
node->parent->parent->color = CBinaryTreeNode<T>::RED;
RightRotate(node->parent->parent);
}
} else { // symmetric to left
y = node->parent->parent->left; // uncle node
if (y->color == CBinaryTreeNode<T>::RED) {
node->parent->color = CBinaryTreeNode<T>::BLACK;
y->color = CBinaryTreeNode<T>::BLACK;
node->parent->parent->color = CBinaryTreeNode<T>::RED;
node = node->parent->parent;
} else {
if (node == node->parent->left) {
node = node->parent;
RightRotate(node);
}
node->parent->color = CBinaryTreeNode<T>::BLACK;
node->parent->parent->color = CBinaryTreeNode<T>::RED;
LeftRotate(node->parent->parent);
}
}
}
this->root->color = CBinaryTreeNode<T>::BLACK;
}
template <typename T>
void CRedBlackTree<T>::DeleteFixup(CBinaryTreeNode<T>* node)
{
CBinaryTreeNode<T>* w = node;
while (node != this->root && node->color == CBinaryTreeNode<T>::BLACK) {
if (node == node->parent->left) {
w = node->parent->right; // brother node
if (w->color == CBinaryTreeNode<T>::RED) {
w->color = CBinaryTreeNode<T>::BLACK;
w->parent->color = CBinaryTreeNode<T>::RED;
LeftRotate(node->parent);
w = node->parent->right;
}
if (w->left->color == CBinaryTreeNode<T>::BLACK && w->right->color == CBinaryTreeNode<T>::BLACK) {
w->color = CBinaryTreeNode<T>::RED;
node = node->parent;
} else {
if (w->right->color == CBinaryTreeNode<T>::BLACK) {
w->left->color = CBinaryTreeNode<T>::BLACK;
w->color = CBinaryTreeNode<T>::RED;
RightRotate(w);
w = node->parent->right;
}
w->color = node->parent->color;
w->right->color = CBinaryTreeNode<T>::BLACK;
node->parent->color = CBinaryTreeNode<T>::BLACK;
LeftRotate(node->parent);
node = this->root;
}
} else {
w = node->parent->left;
if (w->color == CBinaryTreeNode<T>::RED) {
w->color = CBinaryTreeNode<T>::BLACK;
w->parent->color = CBinaryTreeNode<T>::RED;
RightRotate(node->parent);
w = node->parent->left;
}
if (w->left->color == CBinaryTreeNode<T>::BLACK && w->right->color == CBinaryTreeNode<T>::BLACK) {
w->color = CBinaryTreeNode<T>::RED;
node = node->parent;
} else {
if (w->left->color == CBinaryTreeNode<T>::BLACK) {
w->right->color = CBinaryTreeNode<T>::BLACK;
w->color = CBinaryTreeNode<T>::RED;
LeftRotate(w);
w = node->parent->left;
}
w->color = node->parent->color;
w->left->color = CBinaryTreeNode<T>::BLACK;
node->parent->color = CBinaryTreeNode<T>::BLACK;
RightRotate(node->parent);
node = this->root;
}
}
}
node->color = CBinaryTreeNode<T>::BLACK;
}
template <typename T>
void CRedBlackTree<T>::LeftRotate(CBinaryTreeNode<T>* node)
{
CBinaryTreeNode<T>* y = node->right;
node->right = y->left;
if (y->left != &CBinarySortTree<T>::sentinel)
y->left->parent = node;
y->parent = node->parent;
if (node->parent == &CBinarySortTree<T>::sentinel)
this->root = y;
else if (node == node->parent->left)
node->parent->left = y;
else
node->parent->right = y;
y->left = node;
node->parent = y;
}
template <typename T>
void CRedBlackTree<T>::RightRotate(CBinaryTreeNode<T>* node)
{
CBinaryTreeNode<T>* x = node->left;
node->left = x->right;
if (x->right != &CBinarySortTree<T>::sentinel)
x->right->parent = node;
x->parent = node->parent;
if (node->parent == &CBinarySortTree<T>::sentinel)
this->root = x;
else if (node->parent->left == node)
node->parent->left = x;
else
node->parent->right = x;
x->right = node;
node->parent = x;
}
#endif
这里简要说明一下,红黑树在二叉搜索树的插入和删除操作基础上还有修正操作,而对Insert的修正操作比较简单,只需要操作被插入的结点,所以直接重用了二叉搜索树的Insert,而对Delete的修正操作就比较复杂些,所以这里重新实现了Delete操作,其实逻辑跟二叉搜索树的删除操作大体上相同。
最后,测试红黑树的代码,rbt_test.cpp:
#include "rbt.h"
int main(int argc, const char **argv)
{
int key[] = { 12, 1, 9, 2, 0, 11, 7, 19, 4, 15, 18, 5, 14, 13, 10, 16, 6, 3, 8, 17 };
CRedBlackTree<int> rbt;
cout << "original key: " << endl;
for (size_t i = 0; i < sizeof(key) / sizeof(int); ++i)
cout << key[i] << ' ';
cout << endl;
for (size_t i = 0; i < sizeof(key) / sizeof(int); ++i) {
rbt.Insert(key[i]);
cout << "after insertion: " << key[i] << endl;
rbt.InorderWalk();
}
cout << endl;
for (size_t i = 0; i < sizeof(key) / sizeof(int); ++i) {
CBinaryTreeNode<int>* del = rbt.Search(key[i]);
if (del) {
cout << "after " << i + 1 << " time(s) deletion: " << endl;
rbt.Delete(&del);
rbt.InorderWalk();
cout << endl;
}
}
return 0;
}
同样,验证时使用到如下网址的图片,在此表示感谢:http://saturnman.blog.163.com/blog/static/557611201097221570/。
附:
C++的一大特性是多态,由于二叉搜索树类是红黑树类的父类,所以,我们可以使用二叉搜索树类的指针或者引用在运行时动态绑定红黑树的成员函数,实现多态,rbt_test.cpp:
#include "rbt.h"
using std::runtime_error;
int main(int argc, const char **argv)
{
int key[] = { 12, 1, 9, 2, 0, 11, 7, 19, 4, 15, 18, 5, 14, 13, 10, 16, 6, 3, 8, 17 };
CBinarySortTree<int>* pbst = NULL;
try {
pbst = new CRedBlackTree<int>();
if (!pbst)
throw runtime_error("new object failed.");
cout << "original key: " << endl;
for (size_t i = 0; i < sizeof(key) / sizeof(int); ++i)
cout << key[i] << ' ';
cout << endl;
for (size_t i = 0; i < sizeof(key) / sizeof(int); ++i) {
pbst->Insert(key[i]);
cout << "after insertion: " << key[i] << endl;
pbst->InorderWalk();
}
cout << endl;
for (size_t i = 0; i < sizeof(key) / sizeof(int); ++i) {
CBinaryTreeNode<int>* del = pbst->Search(key[i]);
if (del) {
cout << "after " << i + 1 << " time(s) deletion: " << endl;
pbst->Delete(&del);
pbst->InorderWalk();
cout << endl;
}
}
delete pbst;
} catch (...) {
if (pbst)
delete pbst;
}
pbst = NULL;
return 0;
}