红黑树的C++实现与解析
2012-07-27 16:06
483 查看
所谓红黑树,就是平衡的扩充二叉搜索树,红黑树与AVL都是BST的平衡版本,相比AVL的完全平衡,红黑树只要求局部平衡,因此当向红黑树中插入和删除节点时,需要的调整比AVL要少,统计性能要好于AVL树,C++ STL中的map、set、multimap和multiset都应用了红黑树的变体。本文主要对红黑树的节点插入和节点删除进行解析。对于插入节点和删除节点本文都会总结一个基本的模板。
首先来看一下红黑树的特点:
1、红黑树的根节点为黑色
2、红黑树中扩充的外部节点都是黑色节点
3、红色节点的两个子节点都是黑色节点,不允许两个连续的红色节点
4、任何节点到其子孙的外部节点的每条简单路径都包含相同数目的黑色节点
一、向红黑树中插入节点
因为红黑树上面的第4个特点,因此当向红黑树中插入新的节点时,应该将新节点标注为红色。向红黑树中插入节点看的是插入节点的父节点和叔父节点。
对于以下讨论中,我们新插入的节点是节点D或是节点E,哪一个为红色,哪一个就是我们新插入的节点。
1、当插入新节点的父节点是黑色节点时,插入结束
2、当插入新节点的父节点是红色节点并且插入节点的叔父节点是黑色节点时,有以下四种情况,其中情况1、2和情况4、3分别对称,因此此处我们只讨论情况1、2
在插入节点这一块中,我们提取出的基本模板是情况1,对于情况1,我们进行的调整如下图所示:
对于调整,我们的原则,是调整后对外界没有影响,对于上图中也就是说,B节点应该与A节点颜色相同,也就是黑色,因此为了保持B的左右子树的黑色节点数相同,应该将A节点变为红色,因此情况1的调整结束。
对于情况2.此处我们选情况1为模板的意思就是当遇到情况2时,先将情况2调整成情况1,然后再按照情况1的模式调整即可,将情况1调整为情况2的方式如下图:
由图中可以看出,我们只需要调整节点B和节点E位置,而不需要换色,因此调整比较简单,然后按照情况1调整即可。
3、当插入节点的父节点是红色节点并且插入节点的叔父节点也是红色节点时,我们进行如下调整:
就是将新插入节点D的父节点B与叔父节点C均变为黑色,然后将D的祖父节点A变为红色,这样将A节点当成是新插入的节点向上进行红红调整即可。
二、删除红黑树中的节点
对于删除节点,如果我们要删除的节点刚好是叶节点,那么就将其进行删除然后进行调整,如果要删除的节点不是叶节点,那么就寻找要删除节点的左子树的最大值节点M,然后将该最大值转存到要删除的节点处,然后将节点M删除,也就是说删除的也是叶子节点,因此我们讨论删除叶子节点时对红黑树的调整。
1、当删除的叶子节点是红色节点时,直接删除就好,不需要调整
2、当删除的节点是黑色节点时,该删除节点处就由扩展的黑色节点N代替,而且为了保持红黑树的特点4,该N节点就成为双黑节点,也就是说,N的黑色代表两次时,可以保证红黑树的特点4.
删除红黑树的节点考虑的是双黑节点的兄弟节点,以及其兄弟节点的子节点。
下面我们在删除节点的调整中提取处一个基本模板,如下图所示:
其中节点N为双黑节点,图中无色节点表示是红色还是黑色无关紧要,其中右边的图是左边基本模板调整后的图。对于调整,基本要求还是对外部没有影响,因此,调整后,B的颜色与A的相同,这样节点D就应该变为黑色,作为原来B节点的补充,A也应该为黑色,这样才能使这颗子树相对于外部的黑色节点数不变,以及新子树中B的左右子树中的黑色节点数相同。
然后我们来描述其他情况:
(1)当将基本模板中D为黑色节点,而C为红色节点,如下图所示:
从上图可知,我们只需要将B分支下的子树进行简单的调整,就可以调整成右图中的形式,也就是基本模板中的情况,然后按照基本模板的处理方法处理即可。
(2)当基本模板中C和D均为黑色时,只需要将B变成红色,这样A的左右子树中的黑色节点数边相等,但对于外部,A节点往下的子树的黑色节点少了1个,因此如果A节点是红色的,将A变为黑色即可,如果A本身就是黑色那么将A设为双黑节点继续向上调整即可。
(3)当双黑节点N的兄弟节点B为红色时,如下所示调整:
从上图可知,这样便又调整成了双黑节点的兄弟节点为黑色节点的状况,按照上面的方法调整即可。
红黑树的一个实现如下:
首先来看一下红黑树的特点:
1、红黑树的根节点为黑色
2、红黑树中扩充的外部节点都是黑色节点
3、红色节点的两个子节点都是黑色节点,不允许两个连续的红色节点
4、任何节点到其子孙的外部节点的每条简单路径都包含相同数目的黑色节点
一、向红黑树中插入节点
因为红黑树上面的第4个特点,因此当向红黑树中插入新的节点时,应该将新节点标注为红色。向红黑树中插入节点看的是插入节点的父节点和叔父节点。
对于以下讨论中,我们新插入的节点是节点D或是节点E,哪一个为红色,哪一个就是我们新插入的节点。
1、当插入新节点的父节点是黑色节点时,插入结束
2、当插入新节点的父节点是红色节点并且插入节点的叔父节点是黑色节点时,有以下四种情况,其中情况1、2和情况4、3分别对称,因此此处我们只讨论情况1、2
在插入节点这一块中,我们提取出的基本模板是情况1,对于情况1,我们进行的调整如下图所示:
对于调整,我们的原则,是调整后对外界没有影响,对于上图中也就是说,B节点应该与A节点颜色相同,也就是黑色,因此为了保持B的左右子树的黑色节点数相同,应该将A节点变为红色,因此情况1的调整结束。
对于情况2.此处我们选情况1为模板的意思就是当遇到情况2时,先将情况2调整成情况1,然后再按照情况1的模式调整即可,将情况1调整为情况2的方式如下图:
由图中可以看出,我们只需要调整节点B和节点E位置,而不需要换色,因此调整比较简单,然后按照情况1调整即可。
3、当插入节点的父节点是红色节点并且插入节点的叔父节点也是红色节点时,我们进行如下调整:
就是将新插入节点D的父节点B与叔父节点C均变为黑色,然后将D的祖父节点A变为红色,这样将A节点当成是新插入的节点向上进行红红调整即可。
二、删除红黑树中的节点
对于删除节点,如果我们要删除的节点刚好是叶节点,那么就将其进行删除然后进行调整,如果要删除的节点不是叶节点,那么就寻找要删除节点的左子树的最大值节点M,然后将该最大值转存到要删除的节点处,然后将节点M删除,也就是说删除的也是叶子节点,因此我们讨论删除叶子节点时对红黑树的调整。
1、当删除的叶子节点是红色节点时,直接删除就好,不需要调整
2、当删除的节点是黑色节点时,该删除节点处就由扩展的黑色节点N代替,而且为了保持红黑树的特点4,该N节点就成为双黑节点,也就是说,N的黑色代表两次时,可以保证红黑树的特点4.
删除红黑树的节点考虑的是双黑节点的兄弟节点,以及其兄弟节点的子节点。
下面我们在删除节点的调整中提取处一个基本模板,如下图所示:
其中节点N为双黑节点,图中无色节点表示是红色还是黑色无关紧要,其中右边的图是左边基本模板调整后的图。对于调整,基本要求还是对外部没有影响,因此,调整后,B的颜色与A的相同,这样节点D就应该变为黑色,作为原来B节点的补充,A也应该为黑色,这样才能使这颗子树相对于外部的黑色节点数不变,以及新子树中B的左右子树中的黑色节点数相同。
然后我们来描述其他情况:
(1)当将基本模板中D为黑色节点,而C为红色节点,如下图所示:
从上图可知,我们只需要将B分支下的子树进行简单的调整,就可以调整成右图中的形式,也就是基本模板中的情况,然后按照基本模板的处理方法处理即可。
(2)当基本模板中C和D均为黑色时,只需要将B变成红色,这样A的左右子树中的黑色节点数边相等,但对于外部,A节点往下的子树的黑色节点少了1个,因此如果A节点是红色的,将A变为黑色即可,如果A本身就是黑色那么将A设为双黑节点继续向上调整即可。
(3)当双黑节点N的兄弟节点B为红色时,如下所示调整:
从上图可知,这样便又调整成了双黑节点的兄弟节点为黑色节点的状况,按照上面的方法调整即可。
红黑树的一个实现如下:
#ifndef CM_RBTREE_HPP #define CM_RBTREE_HPP #include "BinarySearchTree.hpp" namespace cm { template<typename T> class RBTreeNode; template<typename T> class RBTreeIterator; template<typename T> class RBTree; template<typename T> class RBTreeNode { public: typedef T VALUE_TYPE; enum Color_t { COLOR_BLACK, COLOR_RED }; public: explicit RBTreeNode(const T& v=T(), Color_t c=COLOR_BLACK) : value_(v) , left_(NIL) , right_(NIL) , parent_(NIL) , color_(c) { } RBTreeNode<T>* left() { return left_; } RBTreeNode<T>* right() { return right_; } RBTreeNode<T>* parent(){ return parent_; } RBTreeNode<T>* left() const { return left_; } RBTreeNode<T>* right() const { return right_; } RBTreeNode<T>* parent() const { return parent_; } const T& value() const { return value_; } Color_t color() const { return color_; } void left(RBTreeNode<T>* node) { left_ = node; } void right(RBTreeNode<T>* node) { right_ = node; } void parent(RBTreeNode<T>* node){ parent_ = node; } void value(const T& value) { value_ = value; } void color(Color_t c) { color_ = c; } operator bool() const { return this != NIL; } bool operator !() const { return this == NIL; } public: static RBTreeNode<T>* NIL; private: T value_; RBTreeNode<T>* left_; RBTreeNode<T>* right_; RBTreeNode<T>* parent_; Color_t color_; }; template<typename T> RBTreeNode<T>* RBTreeNode<T>::NIL(new RBTreeNode<T>()); template<typename T> class RBTree: public BinarySearchTree_T< RBTreeNode<T> > { public: typedef RBTreeNode<T> Node; public: size_t bh() const { return this->bh(this->getRoot()); } size_t bh(const Node* node) const { Node* n = node; size_t h = ; while (n) { if (n->color() == Node::COLOR_BLACK) { ++h; } n = n->left(); } return h; } size_t insert(const T& key) { Node* z = new Node(key, Node::COLOR_RED); // 要插入的节点 Node* y = Node::NIL; // y 是 x 的父节点 Node* x = this->root(); while (x != Node::NIL) { y = x; if (key == x->value()) { return 0; } if (key < x->value()) { x = x->left(); } else { x = x->right(); } } z->parent(y); if (y == Node::NIL) { this->root_ = z; this->root_->parent(Node::NIL); } else { if(key < y->value()) { y->left(z); } else { y->right(z); } } z->left(Node::NIL); z->right(Node::NIL); insert_fixup(z); ++this->size_; return ; } void remove(Node* z) { Node* y = Node::NIL; Node* x = Node::NIL; if (z->left() == Node::NIL || z->right() == Node::NIL) { y = z; } else { //y = this->successor(z); y = z->right(); while (y->left() != Node::NIL) { y = y->left(); } } // x 是 y的唯一孩子 if (y->left() != Node::NIL) { x = y->left(); } else { x = y->right(); } x->parent(y->parent()); if(y->parent() == Node::NIL) { this->root_ = x; } else { if (y == y->parent()->left()) { y->parent()->left(x); } else { y->parent()->right(x); } } if (y != z) { z->value(y->value()); } if (y->color() == Node::COLOR_BLACK) { this->delete_fixup(x); } delete y; --this->size_; } /// 如果key存在,删除并返回 ,否则返回 size_t remove(const T& key) { Node* node = this->find(key); if (node != Node::NIL) { this->remove(node); return ; } return ; } private: void left_rotate(Node* x) { Node* y = x->right(); // 把y的左子数变成x的右子树 x->right(y->left()); if (y->left() != Node::NIL) { y->left()->parent(x); } if (y != Node::NIL) { y->parent(x->parent()); } if (x->parent() == Node::NIL) { this->root_ = y; } else { if (x == x->parent()->left()) { x->parent()->left(y); } else { x->parent()->right(y); } } // 把x变成y的左子节点 y->left(x); if (x != Node::NIL) { x->parent(y); } } void right_rotate(Node* x) { Node* y = x->left(); x->left(y->right()); if (y->right() != Node::NIL) { y->right()->parent(x); } if (y != Node::NIL) { y->parent(x->parent()); } if (x->parent() == Node::NIL) { this->root_ = y; } else { if (x == x->parent()->left()) { x->parent()->left(y); } else { x->parent()->right(y); } } y->right(x); if (x != Node::NIL) { x->parent(y); } } void insert_fixup(Node* z) { Node* y = Node::NIL; while (z != this->root() && z->parent()->color() == Node::COLOR_RED) { if (z->parent() == z->parent()->parent()->left()) { y = z->parent()->parent()->right(); if (y->color() == Node::COLOR_RED) { z->parent()->color(Node::COLOR_BLACK); y->color(Node::COLOR_BLACK); z->parent()->parent()->color(Node::COLOR_RED); z = z->parent()->parent(); } else { if (z == z->parent()->right()) { z = z->parent(); this->left_rotate(z); } z->parent()->color(Node::COLOR_BLACK); z->parent()->parent()->color(Node::COLOR_RED); this->right_rotate(z->parent()->parent()); } } else { y = z->parent()->parent()->left(); if (y->color() == Node::COLOR_RED) { z->parent()->color(Node::COLOR_BLACK); y->color(Node::COLOR_BLACK); z->parent()->parent()->color(Node::COLOR_RED); z = z->parent()->parent(); } else { if (z == z->parent()->left()) { z = z->parent(); this->right_rotate(z); } z->parent()->color(Node::COLOR_BLACK); z->parent()->parent()->color(Node::COLOR_RED); this->left_rotate(z->parent()->parent()); } } } this->root()->color(Node::COLOR_BLACK); } void delete_fixup(Node* x) { Node* w = Node::NIL; while (x != this->root() && x->color() == Node::COLOR_BLACK) { if (x == x->parent()->left()) { w = x->parent()->right(); if (w->color() == Node::COLOR_RED) { w->color(Node::COLOR_BLACK); x->parent()->color(Node::COLOR_RED); this->left_rotate(x->parent()); w = x->parent()->right(); } if (w->left()->color() == Node::COLOR_BLACK && w->right()->color() == Node::COLOR_BLACK) { w->color(Node::COLOR_RED); x = x->parent(); } else { if (w->right()->color() == Node::COLOR_BLACK) { w->left()->color(Node::COLOR_BLACK); w->color(Node::COLOR_RED); right_rotate(w); w = x->parent()->right(); } w->color(x->parent()->color()); x->parent()->color(Node::COLOR_BLACK); w->right()->color(Node::COLOR_BLACK); left_rotate(x->parent()); x = this->root(); } } else { w = x->parent()->left(); if (w->color() == Node::COLOR_RED) { w->color(Node::COLOR_BLACK); x->parent()->color(Node::COLOR_RED); right_rotate(x->parent()); w = x->parent()->left(); } if (w->right()->color() == Node::COLOR_BLACK && w->left()->color() == Node::COLOR_BLACK) { w->color(Node::COLOR_RED); x = x->parent(); } else { if (w->left()->color() == Node::COLOR_BLACK) { w->right()->color(Node::COLOR_BLACK); w->color(Node::COLOR_RED); left_rotate(w); w = x->parent()->left(); } w->color(x->parent()->color()); x->parent()->color(Node::COLOR_BLACK); w->left()->color(Node::COLOR_BLACK); right_rotate(x->parent()); x = this->root(); } } } x->color(Node::COLOR_BLACK); } }; template<typename T> class RBTreeIterator { public: RBTreeIterator() : tree_(RBTreeNode<T>::NIL), current_(RBTreeNode<T>::NIL) { } RBTreeIterator(RBTree<T>& tree, typename RBTree<T>::Node* current) : tree_(tree), current_(current) { } const T& operator*() const { return current_->value(); } T* operator->() { return current_; } bool operator==(const RBTreeIterator& rhs) const { return current_ == rhs.current_; } bool operator!=(const RBTreeIterator& rhs) const { return current_ != rhs.current_; } RBTreeIterator& operator++() { current_ = tree_.successor(current_); return *this; } private: RBTree<T>& tree_; typename RBTree<T>::Node* current_; }; } // end namespace cm #endif // CM_RBTREE_HPP
相关文章推荐
- 常见设计模式的解析和实现(C++)之十一-TemplateMethod模式
- 常见设计模式的解析和实现(C++)之二十一-完结篇
- 常见设计模式的解析和实现(C++)之十八-Iterator模式
- C++多态的实现及原理详细解析
- 常见设计模式的解析和实现(C++)之九—Decorator模式
- 常见设计模式解析和实现(C++)Adapt模式
- 红黑树C++模板和仿函数实现
- INI解析模块的C++实现
- 常见设计模式的解析和实现(C++)之一-Factory模式
- 常见设计模式的解析和实现(C++)之六-Adapt模式
- C/C++——strcpy函数的实现 和解析1
- C++ boost库中的sp_counted_base实现解析
- 常见设计模式的解析和实现(C++)之十二-ChainOfResponsibility模式
- 常见设计模式的解析和实现(C++)之十七-State模式
- 常见设计模式的解析和实现(C++)之五-Singleton模式
- 数据结构图文解析之:二叉堆详解及C++模板实现
- 数据结构图文解析之:数组、单链表、双链表介绍及C++模板实现
- 设计模式精解-GoF 23种设计模式解析附C++实现源码
- 设计模式的解析和实现(C++)之六-Adapt模式
- CSP考试 2016年04月第3题 路径解析 C++实现