1、平衡二叉树
平衡二叉树有许多种类型,包括AVL-tree、RB-tree、AA-tree,其中最被广泛运用于STL的是RB-tree(红黑树)。二叉搜索树的节点放置规则是:任何节点的键值一定大于其左子树中的每一个节点的键值,并小于其右子树中的每一个节点的键值。
2、AVL-tree
AVL-tree是一个“加上了额外平衡条件”的二叉搜索树,其平衡条件的建立是为了确保整棵树的深度为O(logN)。AVL-tree要求任何节点的左右子树高度相差最多1。由于只有插入点至根节点路径是哪个的各节点可能改变平衡状态,因此只要调整其中最深的那个节点,便可使整棵树重新获得平衡。
AVL-tree平衡被破坏意味着某个节点X的左右两棵树的高度相差2,因此可分为四种情况:
- 插入点位于X的左子节点的左子树——左左
- 插入点位于X的左子节点的右子树——左右
- 插入点位于X的右子节点的左子树——右左
- 插入点位于X的右子节点的右子树——右右
对于左左或右右属于外侧插入,可以采用单旋转操作调整解决;对于左右或右左属于内侧插入,可以采用双旋转操作调整解决。
(1)单旋转
以左左情况举例,为了调整平衡状态,我们希望将A子树提高一层,并将C子树下降一层,对k2节点采取右旋操作:将B挂到k2的左子节点,将k2的父节点变为k1的父节点,将k2挂到k1的右子节点。
(2)双旋转
以左右情况举例,单旋转无法解决这种情况,需要双旋转实现,以k2为新的根节点,这使得k1必须成为k2的左子节点,k3必须成为k2的右子节点。先对k1左旋,在对k3右旋。
3、RB-tree概述
RB-tree必须满足一下规则:
- 每个节点不是红色就是黑色
- 根节点为黑色
- 如果父节点为红色,其子节点必须为黑色(不允许出现红-红的情况)
- 任一节点至NULL树尾端的任何路径,所含的黑节点数必须相同(新增节点必须红色)
根据规则4,新增节点必须为红色;根据规则3,新增节点的父节点必须是黑色;如果新增节点未能符合上述条件时,就必须调整颜色并旋转树形。RB-tree和AVL-tree的区别在于:平衡条件不同,AVL-tree是左右子树高度大于1的时候调整平衡,RB-tree是不满足颜色条件时调整平衡。
总结:相较于AVL-tree,RB-tree的平衡性比AVL-tree弱,但RB-tree的搜寻平均效率和AVL-tree几乎相同,RB-tree不仅在树形的平衡性上表现不错,在效率表现和实现复杂度上也保持相当的平衡,所以运用甚广。RB-tree比AVL-tree插入节点后平衡的判断条件更简单一点,只要通过父节点的颜色判断是否平衡,然后通过伯父节点的颜色就知道怎么去平衡,而AVL-tree需要向上计算比较节点的高度是否大于1判断是否需要平衡以及怎样平衡。
RB-tree插入节点调整颜色并旋转树形情况:以插入节点的父节点为祖父节点的左子节点为例,当插入节点的父节点为红色时,就需要判断伯父节点颜色来调整颜色并旋转树形
(1)插入节点的伯父节点存在且为红
这种情况处理最简单了,只要将父节点、伯父节点、祖父节点这三个节点直接改变颜色即可:①将父节点设为黑色,②伯父节点设为黑色,③祖父节点设为红色。这样对于目前这几个节点已经满足RB-tree的条件了,但还需要检查祖父节点的父节点是否满足条件:因为祖父节点变为红色,如果祖父节点的父节点也是红色则需要继续向上回溯(while循环)调整颜色并旋转树形。
(2)插入节点的无伯父节点或为黑色,且插入节点为其父节点的右节点
这种情况只需要对插入节点的祖父节点右旋,同时改变父节点和祖父节点的颜色即可:①改变父节点颜色为黑色,②改变祖父节点颜色为红色,③对祖父节点右旋。
(3)插入节点的无伯父节点或为黑色,且插入节点为其父节点的左节点
这种情况只需要双旋转操作,对插入节点的父节点左旋,然后对祖父节点右旋,同时改变父节点和祖父节点的颜色即可:①对父节点左旋,②改变父节点颜色为黑色,③改变祖父节点颜色为红色,④对祖父节点右旋。相较于(2)唯一不同的是多了一步对插入节点的父节点左旋。
4、RB-tree的节点
RB-tree的节点设计,为了有更大的弹性,节点分为两层,__rb_tree_node_base和__rb_tree_node,__rb_tree_node继承自__rb_tree_node_base。所以RB-tree节点最终有四个数据成员:color、parent指针、left指针、right指针、value_field节点值。
typedef bool __rb_tree_color_type;
const __rb_tree_color_type __rb_tree_red = false;
const __rb_tree_color_type __rb_tree_black = true;
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;
};
5、RB-tree的迭代器
RB-tree的迭代器为了更大的弹性,实现分为两层,__rb_tree_base_iterator和__rb_tree_iterator,__rb_tree_iterator继承自__rb_tree_base_iterator,主要是继承了increment()和decrement()函数,用于迭代器operator++和operator--的操作实现。RB-tree迭代器属于双向迭代器,但不具备随机定位能力,和list的迭代器十分相似。RB-tree的迭代器前进或后退的举止行为完全依据二叉搜索树的节点排列法则,operator++是找到比当前节点略大的下一个节点位置,operator--是找到比当前节点略小的上一个节点位置。
(1)increment()
- 如果当前节点存在右子树,那么operator++就是右子树的最左节点位置
- 如果当前节点不存在右子树,那么当前节点是某祖父节点的左子树的最大节点值,这就需要当前节点一直向上回溯到这个祖父节点就是operator++位置略大于当前节点值,具体做法就是当前节点一直向上回溯到当前节点不是父节点的右孩子,那么此父节点y就是要找祖父节点,返回node=y。
- 如果没有找到这个祖父节点,就是当前节点就是根节点且没有右子节点的情况,此时y指向了root,node指向了header,此时node->righht==y,所以直接返回node不需要令node=y。相当于是RB-tree中最大的一个节点operator++指向header节点也就是end()。
(2)decrement()
- 如果当前节点是end(),也就是header节点,那么operator--就是指向当前RB-tree最大节点值也就是header->right
- 如果当前节点存在左子树,那么operator--就是左子树的最右节点位置
- 如果当前节点不存在左子树,那么当前节点是某祖父节点的右子树的最小节点值,这就需要当前节点一直向上回溯到这个祖父节点就是operator--位置略小于当前节点值,具体做法就是当前节点一直向上回溯到当前节点不是父节点的左孩子,那么此父节点y就是要找祖父节点,返回node=y。
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;
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;
}
if (node->right != y)
node = y;
}
}
void decrement()
{
if (node->color == __rb_tree_red &&
node->parent->parent == node)
node = node->right;
else if (node->left != 0) {
base_ptr y = node->left;
while (y->right != 0)
y = y->right;
node = 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; }
pointer operator->() const { return &(operator*()); }
self& operator++() { increment(); return *this; }
self operator++(int) {
self tmp = *this;
increment();
return tmp;
}
self& operator--() { decrement(); return *this; }
self operator--(int) {
self tmp = *this;
decrement();
return tmp;
}
};
6、RB-tree的数据结构
RB-tree有一个header节点,这个节点的目的是对于树的各种操作注意边界情况的发生,也就是走到根节点时要特殊处理。header和root节点互为父节点,header的left指向最小的节点leftmost,header的right指向最大的节点rightmost,header的color为红色,RB-tree的end()指向这个header节点,RB-tree的begin()指向最小的节点也就是header的left指向的节点,RB-tree的root()返回的是header->parent也就是root节点。
template <class Key, class Value, class KeyOfValue, class Compare,
class Alloc = alloc>
class rb_tree {
protected:
typedef void* void_pointer;
typedef __rb_tree_node_base* base_ptr;
typedef __rb_tree_node<Value> rb_tree_node;
typedef simple_alloc<rb_tree_node, Alloc> rb_tree_node_allocator;
typedef __rb_tree_color_type color_type;
public:
typedef Key key_type;
typedef Value value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef rb_tree_node* link_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
protected:
link_type get_node() { return rb_tree_node_allocator::allocate(); }
void put_node(link_type p) { rb_tree_node_allocator::deallocate(p); }
link_type create_node(const value_type& x) {
link_type tmp = get_node();
__STL_TRY {
construct(&tmp->value_field, x);
}
__STL_UNWIND(put_node(tmp));
return tmp;
}
link_type clone_node(link_type x) {
link_type tmp = create_node(x->value_field);
tmp->color = x->color;
tmp->left = 0;
tmp->right = 0;
return tmp;
}
void destroy_node(link_type p) {
destroy(&p->value_field);
put_node(p);
}
protected:
size_type node_count; // keeps track of size of tree
link_type header;
Compare key_compare;
link_type& root() const { return (link_type&) header->parent; }
link_type& leftmost() const { return (link_type&) header->left; }
link_type& rightmost() const { return (link_type&) header->right; }
static link_type& left(link_type x) { return (link_type&)(x->left); }
static link_type& right(link_type x) { return (link_type&)(x->right); }
static link_type& parent(link_type x) { return (link_type&)(x->parent); }
static reference value(link_type x) { return x->value_field; }
static const Key& key(link_type x) { return KeyOfValue()(value(x)); }
static color_type& color(link_type x) { return (color_type&)(x->color); }
static link_type& left(base_ptr x) { return (link_type&)(x->left); }
static link_type& right(base_ptr x) { return (link_type&)(x->right); }
static link_type& parent(base_ptr x) { return (link_type&)(x->parent); }
static reference value(base_ptr x) { return ((link_type)x)->value_field; }
static const Key& key(base_ptr x) { return KeyOfValue()(value(link_type(x)));}
static color_type& color(base_ptr x) { return (color_type&)(link_type(x)->color); }
static link_type minimum(link_type x) {
return (link_type) __rb_tree_node_base::minimum(x);
}
static link_type maximum(link_type x) {
return (link_type) __rb_tree_node_base::maximum(x);
}
public:
typedef __rb_tree_iterator<value_type, reference, pointer> iterator;
typedef __rb_tree_iterator<value_type, const_reference, const_pointer>
const_iterator;
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
typedef reverse_bidirectional_iterator<iterator, value_type, reference,
difference_type>
reverse_iterator;
typedef reverse_bidirectional_iterator<const_iterator, value_type,
const_reference, difference_type>
const_reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
private:
iterator __insert(base_ptr x, base_ptr y, const value_type& v);
link_type __copy(link_type x, link_type p);
void __erase(link_type x);
void init() {
header = get_node();
color(header) = __rb_tree_red; // used to distinguish header from
// root, in iterator.operator++
root() = 0;
leftmost() = header;
rightmost() = header;
}
public:
// allocation/deallocation
rb_tree(const Compare& comp = Compare())
: node_count(0), key_compare(comp) { init(); }
rb_tree(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& x)
: node_count(0), key_compare(x.key_compare)
{
header = get_node();
color(header) = __rb_tree_red;
if (x.root() == 0) {
root() = 0;
leftmost() = header;
rightmost() = header;
}
else {
__STL_TRY {
root() = __copy(x.root(), header);
}
__STL_UNWIND(put_node(header));
leftmost() = minimum(root());
rightmost() = maximum(root());
}
node_count = x.node_count;
}
~rb_tree() {
clear();
put_node(header);
}
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>&
operator=(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& x);
public:
// accessors:
Compare key_comp() const { return key_compare; }
iterator begin() { return leftmost(); }
const_iterator begin() const { return leftmost(); }
iterator end() { return header; }
const_iterator end() const { return header; }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
bool empty() const { return node_count == 0; }
size_type size() const { return node_count; }
size_type max_size() const { return size_type(-1); }
void swap(rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& t) {
__STD::swap(header, t.header);
__STD::swap(node_count, t.node_count);
__STD::swap(key_compare, t.key_compare);
}
public:
// insert/erase
pair<iterator,bool> insert_unique(const value_type& x);
iterator insert_equal(const value_type& x);
iterator insert_unique(iterator position, const value_type& x);
iterator insert_equal(iterator position, const value_type& x);
void erase(iterator position);
size_type erase(const key_type& x);
void erase(iterator first, iterator last);
void erase(const key_type* first, const key_type* last);
void clear() {
if (node_count != 0) {
__erase(root());
leftmost() = header;
root() = 0;
rightmost() = header;
node_count = 0;
}
}
public:
// set operations:
iterator find(const key_type& x);
const_iterator find(const key_type& x) const;
size_type count(const key_type& x) const;
iterator lower_bound(const key_type& x);
const_iterator lower_bound(const key_type& x) const;
iterator upper_bound(const key_type& x);
const_iterator upper_bound(const key_type& x) const;
pair<iterator,iterator> equal_range(const key_type& x);
pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
public:
// Debugging.
bool __rb_verify() const;
};
7、RB-tree构造与内存管理
link_type get_node() { return rb_tree_node_allocator::allocate(); }
void init() {
header = get_node();
color(header) = __rb_tree_red; // used to distinguish header from
// root, in iterator.operator++
root() = 0;
leftmost() = header;
rightmost() = header;
}
8、RB-tree元素操作
(1)元素插入操作insert_unique()和insert_equal()
先通过insert_unique()或insert_equal()找到插入的位置的父节点,然后调用__insert函数进行插入操作,最后调用__rb_tree_rebalance函数对RB-tree调整平衡操作
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::insert_equal(const Value& v)
{
link_type y = header;
link_type x = root();
while (x != 0) {
y = x;
x = key_compare(KeyOfValue()(v), key(x)) ? left(x) : right(x);
}
return __insert(x, y, v);
}
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
pair<typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator, bool>
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::insert_unique(const Value& v)
{
link_type y = header;
link_type x = root();
bool comp = true;
while (x != 0) {
y = x;
comp = key_compare(KeyOfValue()(v), key(x));
x = comp ? left(x) : right(x);
}
iterator j = iterator(y);
if (comp)
if (j == begin())
return pair<iterator,bool>(__insert(x, y, v), true);
else
--j;
if (key_compare(key(j.node), KeyOfValue()(v)))
return pair<iterator,bool>(__insert(x, y, v), true);
return pair<iterator,bool>(j, false);
}
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
__insert(base_ptr x_, base_ptr y_, const Value& v) {
link_type x = (link_type) x_;
link_type y = (link_type) y_;
link_type z;
if (y == header || x != 0 || key_compare(KeyOfValue()(v), key(y))) {
z = create_node(v);
left(y) = z; // also makes leftmost() = z when y == header
if (y == header) {
root() = z;
rightmost() = z;
}
else if (y == leftmost())
leftmost() = z; // maintain leftmost() pointing to min node
}
else {
z = create_node(v);
right(y) = z;
if (y == rightmost())
rightmost() = z; // maintain rightmost() pointing to max node
}
parent(z) = y;
left(z) = 0;
right(z) = 0;
__rb_tree_rebalance(z, header->parent);
++node_count;
return iterator(z);
}
(2)调整RB-tree平衡(旋转及改变颜色)
RB-tree插入节点调整颜色并旋转树形情况:以插入节点的父节点为祖父节点的左子节点为例,当插入节点的父节点为红色时,就需要判断伯父节点颜色来调整颜色并旋转树形
i 插入节点的伯父节点存在且为红
这种情况处理最简单了,只要将父节点、伯父节点、祖父节点这三个节点直接改变颜色即可:①将父节点设为黑色,②伯父节点设为黑色,③祖父节点设为红色。这样对于目前这几个节点已经满足RB-tree的条件了,但还需要检查祖父节点的父节点是否满足条件:因为祖父节点变为红色,如果祖父节点的父节点也是红色则需要继续向上回溯(while循环)调整颜色并旋转树形。
ii 插入节点的无伯父节点或为黑色,且插入节点为其父节点的右节点
这种情况只需要对插入节点的祖父节点右旋,同时改变父节点和祖父节点的颜色即可:①改变父节点颜色为黑色,②改变祖父节点颜色为红色,③对祖父节点右旋。
iii 插入节点的无伯父节点或为黑色,且插入节点为其父节点的左节点
这种情况只需要双旋转操作,对插入节点的父节点左旋,然后对祖父节点右旋,同时改变父节点和祖父节点的颜色即可:①对父节点左旋,②改变父节点颜色为黑色,③改变祖父节点颜色为红色,④对祖父节点右旋。相较于(2)唯一不同的是多了一步对插入节点的父节点左旋。
inline void
__rb_tree_rebalance(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{
x->color = __rb_tree_red;
while (x != root && x->parent->color == __rb_tree_red) {
if (x->parent == x->parent->parent->left) {
__rb_tree_node_base* y = x->parent->parent->right;
if (y && y->color == __rb_tree_red) {
x->parent->color = __rb_tree_black;
y->color = __rb_tree_black;
x->parent->parent->color = __rb_tree_red;
x = x->parent->parent;
}
else {
if (x == x->parent->right) {
x = x->parent;
__rb_tree_rotate_left(x, root);
}
x->parent->color = __rb_tree_black;
x->parent->parent->color = __rb_tree_red;
__rb_tree_rotate_right(x->parent->parent, root);
}
}
else {
__rb_tree_node_base* y = x->parent->parent->left;
if (y && y->color == __rb_tree_red) {
x->parent->color = __rb_tree_black;
y->color = __rb_tree_black;
x->parent->parent->color = __rb_tree_red;
x = x->parent->parent;
}
else {
if (x == x->parent->left) {
x = x->parent;
__rb_tree_rotate_right(x, root);
}
x->parent->color = __rb_tree_black;
x->parent->parent->color = __rb_tree_red;
__rb_tree_rotate_left(x->parent->parent, root);
}
}
}
root->color = __rb_tree_black;
}
(3)左旋和右旋操作
左旋:x为父节点旋转的节点,y为x->right
- 将y->left挂到x的右子节点上
- 将x的parent变成y的parent
- 将x挂到y的左子节点
右旋:x为父节点旋转的节点,y为x->left
- 将y->right挂到x的左子节点上
- 将x的parent变成y的parent
- 将x挂到y的右子节点
inline void
__rb_tree_rotate_left(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{
__rb_tree_node_base* y = x->right;
x->right = y->left;
if (y->left !=0)
y->left->parent = x;
y->parent = x->parent;
if (x == root)
root = y;
else if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
y->left = x;
x->parent = y;
}
inline void
__rb_tree_rotate_right(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{
__rb_tree_node_base* y = x->left;
x->left = y->right;
if (y->right != 0)
y->right->parent = x;
y->parent = x->parent;
if (x == root)
root = y;
else if (x == x->parent->right)
x->parent->right = y;
else
x->parent->left = y;
y->right = x;
x->parent = y;
}
(4)元素的搜寻
时间复杂度O(logN)
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::find(const Key& k) {
link_type y = header; // Last node which is not less than k.
link_type x = root(); // Current node.
while (x != 0)
if (!key_compare(key(x), k))
y = x, x = left(x);
else
x = right(x);
iterator j = iterator(y);
return (j == end() || key_compare(k, key(j.node))) ? end() : j;
}