三年前磕磕盼盼用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; }红黑树重用了大多数二叉树的接口,将在下一篇介绍。