前言
在上一小节中,我们针对SGISTL中的红黑树的分析完成了一半,接下来的各种操作才是重点的部分。通过以下分析可以了解到红黑树是如何保持平衡的。(STL中实现红黑树定义的重载版本函数太多,我舍去了一部分定义,直接对其声明进行分析,不然篇幅太长)
红黑树的常用操作
clear
上一小节中,析构函数调用了clear
,它的实现如下
void clear() {
if (node_count != 0) {
//调用了__erase
__erase(root());
//将红黑树恢复到初始状态
leftmost() = header;
root() = 0;
rightmost() = header;
node_count = 0;
}
}
重载操作符==
判断两个红黑树是否相等的条件是两者大小相等,
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
inline bool operator==(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& x,
const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& y) {
return x.size() == y.size() && equal(x.begin(), x.end(), y.begin());
}
重载操作符=
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>&
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
operator=(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& x) {
if (this != &x) {
// Note that Key may be a constant type.
clear();
node_count = 0;
key_compare = x.key_compare;
//根结点为null,这就很简单了,直接设置header为初始状态即可
if (x.root() == 0) {
root() = 0;
leftmost() = header;
rightmost() = header;
}
else {
//否则调用__copy函数进行复制
root() = __copy(x.root(), header);
//然后设置header及node_count
leftmost() = minimum(root());
rightmost() = maximum(root());
node_count = x.node_count;
}
}
return *this;
}
插入操作
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) {
/* x为新的值插入点
* y为要插入的点的父节点
* v为插入的值
*/
link_type x = (link_type) x_;
link_type y = (link_type) y_;
//中间变量
link_type z;
//y为header或x不为空或者要插入的值的key与y不重复
if (y == header || x != 0 || key_compare(KeyOfValue()(v), key(y))) {
//创建并初始化值为v的节点
z = create_node(v);
//将header的左孩子设置为z
left(y) = z; // also makes leftmost() = z when y == header
if (y == header) {
//若y为header,将根结点设置为z
//并将header的右孩子设置为z
root() = z;
rightmost() = z;
}
else if (y == leftmost())
//若y为最小节点,则进行调整
//让leftmost()永远指向最左节点
leftmost() = z; // maintain leftmost() pointing to min node
}
else {
//否则创建值为v的节点
z = create_node(v);
//将y的右孩子设置为z
right(y) = z;
//维护rightmost
if (y == rightmost())
rightmost() = z; // maintain rightmost() pointing to max node
}
//设置新节点的父节点、左孩子节点、右孩子节点
parent(z) = y;
left(z) = 0;
right(z) = 0;
//新节点的颜色由__rb_tree_rebalance函数设置并进行调整
__rb_tree_rebalance(z, header->parent);
//节点数加1
++node_count;
//返回迭代器指向新增节点
return iterator(z);
}
//插入新值:节点的键值允许重复
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);
}
/* 插入新值,节点的key不允许重复,若重复则插入无效
* 返回值为pair,第一个元素指向新增节点,第二个元素表示是否插入成功
*/
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);
//若comp为true,则代表应该插入左侧
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);
//返回flase,插入失败
return pair<iterator,bool>(j, false);
}
删除元素
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
inline void
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::erase(it erator position) {
//进行平衡性的调整
link_type y = (link_type) __rb_tree_rebalance_for_erase(position.node,
header->parent,
header->left,
header->right);
//删除节点并将node_count-1
destroy_node(y);
--node_count;
}
//递归删除x为根的所有节点
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
void rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::__erase(link_type x) {
// erase without rebalancing
while (x != 0) {
__erase(right(x));
link_type y = left(x);
destroy_node(x);
x = y;
}
}
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
void rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::erase(const Key* first,
const Key* last) {
while (first != last) erase(*first++);
}
复制操作
template <class K, class V, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<K, V, KeyOfValue, Compare, Alloc>::link_type
rb_tree<K, V, KeyOfValue, Compare, Alloc>::__copy(link_type x, link_type p) {
// structural copy. x and p must be non-null.
//复制x结点
link_type top = clone_node(x);
//x的父节点
top->parent = p;
__STL_TRY {
//存在右子树,则先到最右端
if (x->right)
top->right = __copy(right(x), top);
//对左子树进行拷贝
p = top;
x = left(x);
while (x != 0) {
//拷贝x
link_type y = clone_node(x);
//设置x的父节点的左节点为y
p->left = y;
//设置y的父节点为p
y->parent = p;
//对右子树进行复制
if (x->right)
y->right = __copy(right(x), y);
p = y;
x = left(x);
}
}
__STL_UNWIND(__erase(top));
return top;
}
查找操作
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)
//x键值大于k,则向右走
if (!key_compare(key(x), k))
y = x, x = left(x);
else
//x键值小于k,则向左走
x = right(x);
iterator j = iterator(y);
return (j == end() || key_compare(k, key(j.node))) ? end() : j;
}
平衡性的调整
这里只列出最基本的旋转操作。至于插入或者删除时进行的平衡操作建议参考其他资料,因为会分的情况众多,而我们主要的目的是了解STL
中红黑树的具体实现。
//左旋
inline void
__rb_tree_rotate_left(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{
/* 将x作为旋转点
* y为旋转点的右子节点
*/
__rb_tree_node_base* y = x->right;
x->right = y->left;
if (y->left !=0)
//将左子节点的父节点设置为x
y->left->parent = x;
y->parent = x->parent;
//将x的位置替换成y
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)
{
/* x为旋转点
* y为旋转点的左子节点
__rb_tree_node_base* y = x->left;
x->left = y->right;
if (y->right != 0)
//将右子节点的父节点设置为x
y->right->parent = x;
y->parent = x->parent;
//y替换x
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;
}
小结
本小节中,我们将STL中红黑树剩余的部分进行了分析,由于平衡性的调整方面分的情况太多,需要另写一篇详细的博文才能完全理解,所以在这里就不进行讨论了。
在下一小节中,我们将分析map
容器的实现。