红黑树的性质和插入操作
这部分参考文章 《红黑树操作及实现》
红黑树节点结构
typedef bool __rb_tree_color_type;
const __rb_tree_color_type __rb_tree_red = false; // 红色为0
const __rb_tree_color_type __rb_tree_black = true; // 黑色为1
struct __rb_tree_node_base
{
typedef __rb_tree_color_type color_type;
typedef __rb_tree_node_base* base_ptr;
color_type color; // 节点颜色,红色或黑色
base_ptr parent; // 该指针指向其父节点
base_ptr left; // 指向左节点
base_ptr right; // 指向右节点
//二叉树搜索树,一直向左走,找到最小的值
static base_ptr minimum(base_ptr x)
{
while (x->left != 0) x = x->left;
return x;
}
//二叉搜索树,一直向右走,找最大的值
static base_ptr maximum(base_ptr x)
{
while (x->right != 0) x = x->right;
return x;
}
};
template <class Value>
struct __rb_tree_node : public __rb_tree_node_base
{
typedef __rb_tree_node<Value>* link_type;
Value value_field; //节点的值
};
红黑树节点的结构如下:
红黑树的迭代器
RB-tree迭代器实现分为两层,这种设计理念类似于slist。下图是两层节点结构和双层迭代器结构间的关系,其中主要意义是:__rb_tree_node继承自__rb_tree_node_base,__rb_tree_iterator继承自__rb_tree_base_iterator。
这里主要关注底层迭代器increment()和decrement()这两个操作分别实现迭代器的自加和自减操作,其前进后退举动完全依据二叉搜索树寻找前驱后继节点的规则(二叉搜索树寻找前驱后继规则参考该文章),只是多了一些实现技巧。
代码的实现见最后的完整源代码。这里的实现技巧如下。每当插入新节点时,不但要依据红黑树规则来调整,还有维护header的正确性,使其父节点指向根节点,左子节点指向最小节点,右子节点指向最大节点。
红黑树插入操作
提供了两种插入操作:insert_unique()和insert_equal(),分别在树中插入独一无二的值、插入可以重复的值。有多个版本,重点分析insert_unique(const Value& v)版本。
真正指向插入操作的是__insert()函数。
红黑树源码
//stl_tree.h
#ifndef __SGI_STL_INTERNAL_TREE_H
#define __SGI_STL_INTERNAL_TREE_H
/*
Red-black tree(红黑树)class,用来当做SLT关联容器的底层机制(如set,multiset,map,
multimap)。里面所用的insertion和deletion方法以Cormen, Leiserson 和 Riveset所著的
《算法导论》一书为基础,但是有以下两点不同:
(1)header不仅指向root,也指向红黑树的最左节点,以便用常数时间实现begin(),并且也指向红黑树的最右边节点,以便
set相关泛型算法(如set_union等等)可以有线性时间实现。
(2)当一个即将被删除的节点有两个孩子节点时,它的successor(后继)node is relinked into its place, ranther than copied,
如此一来唯一失效的(invalidated)的迭代器就只是那些referring to the deleted node.
*/
#include <stl_algobase.h>
#include <stl_alloc.h>
#include <stl_construct.h>
#include <stl_function.h>
__STL_BEGIN_NAMESPACE
//定义红色黑色。红色为0,黑色为1
typedef bool __rb_tree_color_type;
const __rb_tree_color_type __rb_tree_red = false;
const __rb_tree_color_type __rb_tree_black = true;
//红黑树Base类
struct __rb_tree_node_base
{
typedef __rb_tree_color_type color_type;
typedef __rb_tree_node_base* base_ptr;
color_type color; // 节点颜色,红或者黑
base_ptr parent; // RB树的许多操作,必须知道其父结点
base_ptr left; // 指向左孩子节点。
base_ptr right; // 指向右孩子节点。
static base_ptr minimum(base_ptr x)
{
while (x->left != 0) x = x->left; // 一直向左走,就会找到最小值
return x; // 这是二叉查找树的性质。同理下面的函数
}
static base_ptr maximum(base_ptr x)
{
while (x->right != 0) x = x->right;
return x;
}
};
//红黑树类,继承Base类
template <class Value>
struct __rb_tree_node : public __rb_tree_node_base
{
typedef __rb_tree_node<Value>* link_type;//指向节点的指针
Value value_field; // 节点的值
};
//迭代器基类,类型为bidirectional_iterator_tag,可以双向移动
struct __rb_tree_base_iterator
{
typedef __rb_tree_node_base::base_ptr base_ptr;//指向红黑树节点指针
typedef bidirectional_iterator_tag iterator_category;
typedef ptrdiff_t difference_type;
//指向红黑树节点的指针,用它来和容器产生关系
base_ptr node;
/*
重载运算符++和--。目的是找到前驱和后继节点。
关于前驱和后继节点的定义,类似二叉查找树。可以在这里找到:
http://blog.csdn.net/u013074465/article/details/41699891
*/
//下面只是为了实现oprerator++的,其他地方不会调用了。
//++是找到其后继节点
void increment()
{
//如果有右孩子,就是找右子树的最小值
if (node->right != 0) { // 如果有右孩子
node = node->right; // 就向右走
while (node->left != 0) // 然后向左走到底
node = node->left;
}
//如果无右子树。那么就找其最低祖先节点,且这个最低祖先节点的左孩子节点
//也是其祖先节点(每个节点就是自己的祖先节点)
else { // 没有右孩子
base_ptr y = node->parent; // 找出父节点
while (node == y->right) { // 如果现行节点本身是个右子节点
node = y; // 就一直上溯,直到「不为右子节点」止。
y = y->parent;
}
/*
若此时的右子节点不等于此时的父节点,此时的父节点即为解答,否则此时的node为解答.
这样做是为了应付一种特殊情况:我们欲寻找根节点的下一个节点。而恰巧根节点无右孩子。
当然,以上特殊做法必须配合RB-tree根节点与特殊header之间的特殊关系,在上面有图
*/
if (node->right != y) // 若此时的右子节点不等于此时的父节点
node = y; // 此时的父节点即为解答
// 否则此时的node为解答
}
}
//查找前驱结点。
void decrement()
{
if (node->color == __rb_tree_red && // 如果是红节点,且
node->parent->parent == node) // 父节点的父节点等于自己
node = node->right; // 状况(1) 右子节点即为解答。
/*
以上情况发生于node为header时(亦即node为end()时)。注意,header之右孩子即
mostright,指向整棵树的max节点。上面有图
*/
//左子树的最大值结点
else if (node->left != 0) {
base_ptr y = node->left;
while (y->right != 0)
y = y->right;
node = y;
}
/*
既非根节点,且无左子树。找其最低祖先节点y,且y的右孩子也是其祖先节点
*/
else {
base_ptr y = node->parent; //找出父节点
while (node == y->left) {
node = y;
y = y->parent;
}
node = y;
}
}
};
//此处为迭代器
template <class Value, class Ref, class Ptr>
struct __rb_tree_iterator : public __rb_tree_base_iterator
{
typedef Value value_type;
typedef Ref reference;
typedef Ptr pointer;
typedef __rb_tree_iterator<Value, Value&, Value*> iterator;
typedef __rb_tree_iterator<Value, const Value&, const Value*> const_iterator;
typedef __rb_tree_iterator<Value, Ref, Ptr> self;
typedef __rb_tree_node<Value>* link_type;
//几个构造函数
__rb_tree_iterator() {}
__rb_tree_iterator(link_type x) { node = x; }
__rb_tree_iterator(const iterator& it) { node = it.node; }
//重载操作符
reference operator*() const { return link_type(node)->value_field; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
//++做了封装,调用的是increment()
self& operator++() { increment(); return *this; }
self operator++(int) {
self tmp = *this;
increment();
return tmp;
}
//调用的是decrement
self& operator--() { decrement(); return *this; }
self operator--(int) {
self tmp = *this;
decrement();
return tmp;
}
};
//两个迭代器相等,意味着它们指向同一个红黑树节点
inline bool operator==(const __rb_tree_base_iterator& x,
const __rb_tree_base_iterator& y) {
return x.node == y.node;
}
inline bool operator!=(const __rb_tree_base_iterator& x,
const __rb_tree_base_iterator& y) {
return x.node != y.node;
}
#ifndef __STL_CLASS_PARTIAL_SPECIALIZATION
//返回迭代器类型
inline bidirectional_iterator_tag
iterator_category(const __rb_tree_base_iterator&) {
return bidirectional_iterator_tag();
}
inline __rb_tree_base_iterator::difference_type*
distance_type(const __rb_tree_base_iterator&) {
return (__rb_tree_base_iterator::difference_type*) 0;
}
template <class Value, class Ref, class Ptr>
inline Value* value_type(const __rb_tree_iterator<Value, Ref, Ptr>&) {
return (Value*) 0;
}
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
// 以下都是全域函式:__rb_tree_rotate_left(), __rb_tree_rotate_right(),
// __rb_tree_rebalance(), __rb_tree_rebalance_for_erase()
/*
新节点必须为红色节点。如果安插处的父节点为红色,就违反了红黑色规则(3)。此时要旋转和改变颜色
*/
//左旋转
inline void
__rb_tree_rotate_left(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{
// x 为旋转点
__rb_tree_node_base* y = x->right; // y为x的右孩子
x->right = y->left;
if (y->left !=0)
y->left->parent = x; // 不要忘了回马枪设置父节点
y->parent = x->parent;
// 令 y 完全顶替 x 的地位(必须将x对其父节点的关系完全接收过来)