三年前磕磕盼盼用C语言写过红黑树,这段时间用C++重写了红黑树,修复了之前代码中的一些错误。记得以前的博客里面就写过使用C++写红黑树更容易些,因为可以重用二叉搜索树的C++代码。照例,首先实现二叉搜索树,然后再实现红黑树。
首先,定义二叉树结点的类,btnode.h:
#ifndef __BTNODE_H__
#define __BTNODE_H__
#include <stdexcept>
#include <typeinfo>
using std::logic_error;
template <typename T>
struct CBinaryTreeNode
{
enum eColor {
RED,
BLACK
};
CBinaryTreeNode(const T& val, CBinaryTreeNode<T>* parent = NULL, CBinaryTreeNode<T>* left = NULL, CBinaryTreeNode<T>* right = NULL, eColor color = RED);
virtual ~CBinaryTreeNode();
virtual bool operator==(const CBinaryTreeNode<T>& node);
virtual bool operator<(const CBinaryTreeNode<T>& node);
virtual bool operator>(const CBinaryTreeNode<T>& node);
T key;
CBinaryTreeNode<T> *parent;
CBinaryTreeNode<T> *left;
CBinaryTreeNode<T> *right;
eColor color;
};
template <typename T>
CBinaryTreeNode<T>::CBinaryTreeNode(const T& val, CBinaryTreeNode<T>* parent, CBinaryTreeNode<T>* left, CBinaryTreeNode<T>* right, eColor color)
{
key = val;
this->parent = parent;
this->left = left;
this->right = right;
this->color = color;
}
template<typename T>
CBinaryTreeNode<T>::~CBinaryTreeNode()
{
}
template <typename T>
bool CBinaryTreeNode<T>::operator==(const CBinaryTreeNode<T>& node)
{
if (typeid(*this) != typeid(node))
throw logic_error("diffrent type objects.");
return this->key == node.key;
}
template <typename T>
bool CBinaryTreeNode<T>::operator<(const CBinaryTreeNode<T>& node)
{
if (typeid(*this) != typeid(node))
throw logic_error("diffrent type objects.");
return this->key < node.key;
}
template <typename T>
bool CBinaryTreeNode<T>::operator>(const CBinaryTreeNode<T>& node)
{
if (typeid(*this) != typeid(node))
throw logic_error("diffrent type objects.");
return this->key > node.key;
}
#endif
然后,定义二叉搜索树的类,bst.h:
#ifndef __BST_H__
#define __BST_H__
#include <iostream>
#include "btnode.h"
using std::cout;
using std::endl;
template <typename T>
class CBinarySortTree
{
public:
CBinarySortTree();
~CBinarySortTree() {}
virtual CBinaryTreeNode<T>* Insert(const T& key);
virtual void Delete(CBinaryTreeNode<T>** del);
virtual CBinaryTreeNode<T>* Search(const T& key) const;
virtual CBinaryTreeNode<T>* Search(CBinaryTreeNode<T>* node, const T& key) const;
virtual void InorderWalk() const;
protected:
CBinaryTreeNode<T>* SearchMinOnRightChild(CBinaryTreeNode<T>* val);
CBinaryTreeNode<T>* Transplant(CBinaryTreeNode<T>* u, CBinaryTreeNode<T>* v);
void InorderWalk(const CBinaryTreeNode<T>* root) const;
CBinaryTreeNode<T>* root;
static CBinaryTreeNode<T> sentinel;
};
template <typename T>
CBinaryTreeNode<T> CBinarySortTree<T>::sentinel(0, &sentinel, &sentinel, &sentinel, CBinaryTreeNode<T>::BLACK);
template <typename T>
CBinarySortTree<T>::CBinarySortTree()
{
root = &sentinel;
root->parent = &sentinel;
root->left = &sentinel;
root->right = &sentinel;
}
template <typename T>
CBinaryTreeNode<T>* CBinarySortTree<T>::Insert(const T& key)
{
CBinaryTreeNode<T> *p = NULL;
if (root == &sentinel) {
p = new CBinaryTreeNode<T>(key, &sentinel, &sentinel, &sentinel);
root = p;
} else {
p = root;
CBinaryTreeNode<T> *parent = &sentinel;
CBinaryTreeNode<T> *node = new CBinaryTreeNode<T>(key, &sentinel, &sentinel, &sentinel);
while (p != &sentinel) {
parent = p;
if (*p < *node)
p = p->right;
else
p = p->left;
}
node->parent = parent;
if (*parent < *node)
parent->right = node;
else
parent->left = node;
p = node;
}
return p;
}
template <typename T>
CBinaryTreeNode<T>* CBinarySortTree<T>::SearchMinOnRightChild(CBinaryTreeNode<T>* node)
{
while (node->left != &sentinel)
node = node->left;
return node;
}
template <typename T>
CBinaryTreeNode<T>* CBinarySortTree<T>::Transplant(CBinaryTreeNode<T>* u, CBinaryTreeNode<T>* v)
{
CBinaryTreeNode<T>* d = NULL;
if (u->parent == &sentinel) {
d = root;
root = v;
} else {
d = u;
if (u == u->parent->left)
u->parent->left = v;
else
u->parent->right = v;
}
v->parent = u->parent;
return d;
}
template <typename T>
void CBinarySortTree<T>::Delete(CBinaryTreeNode<T>** del)
{
CBinaryTreeNode<T>* node = *del;
CBinaryTreeNode<T>* n = &sentinel;
if (node->left == &sentinel && node->right == &sentinel) {
CBinaryTreeNode<T>* parent = node->parent;
if (parent != &sentinel) {
if (parent->left == node)
parent->left = &sentinel;
else
parent->right = &sentinel;
} else {
*del = &sentinel;
root = &sentinel;
}
delete node;
} else if (node->left == &sentinel && node->right != &sentinel) {
n = Transplant(node, node->right);
delete n;
} else if (node->left != &sentinel && node->right == &sentinel) {
n = Transplant(node, node->left);
delete n;
} else {
n = SearchMinOnRightChild(node->right);
if (n->parent != node) {
Transplant(n, n->right);
n->right = node->right;
n->right->parent = n;
}
CBinaryTreeNode<T>* temp = Transplant(node, n);
n->left = node->left;
n->left->parent = n;
delete temp;
}
}
template <typename T>
CBinaryTreeNode<T>* CBinarySortTree<T>::Search(CBinaryTreeNode<T>* node, const T& key) const
{
if (node != &sentinel) {
CBinaryTreeNode<T> n(key);
if (*node < n)
return Search(node->right, key);
else if (*node > n)
return Search(node->left, key);
else
return node;
}
return NULL;
}
template <typename T>
CBinaryTreeNode<T>* CBinarySortTree<T>::Search(const T& key) const
{
return Search(root, key);
}
template <typename T>
void CBinarySortTree<T>::InorderWalk() const
{
InorderWalk(root);
}
template <typename T>
void CBinarySortTree<T>::InorderWalk(const CBinaryTreeNode<T>* node) const
{
const CBinaryTreeNode<T>* p = node;
if (p != &sentinel) {
InorderWalk(p->left);
cout << p->key << ' ';
InorderWalk(p->right);
}
}
#endif
测试二叉搜索树的代码,bst_test.cpp:
#include "bst.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 };
CBinarySortTree<int> bst;
cout << "original key: ";
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)
bst.Insert(key[i]);
cout << "after insertion: ";
bst.InorderWalk();
cout << endl;
for (size_t i = 0; i < sizeof(key) / sizeof(int); ++i) {
CBinaryTreeNode<int>* del = bst.Search(key[i]);
if (del) {
cout << "after " << i + 1 << " time(s) deletion: ";
bst.Delete(&del);
bst.InorderWalk();
cout << endl;
}
}
return 0;
}
红黑树重用了大多数二叉树的接口,将在下一篇介绍。