STL关联式容器之RB-tree(红黑树)_下

RB-tree的数据结构

        下面是rb-tree的定义。你可以看到其中定义有专属的空间配置器,每次用来配置一个节点的大小,也可以看到各种型别定义,用来维护整颗RB-tree的三笔数据(其中有个仿函数,functor,用来表现节点的大小比较方式),以及一些member function的定义或声明。

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;        // 追踪记录树的大小
    link_type header;            // 实现小技巧
    Compare key_compare;         // 节点间键值大小比较function

    link_type& root() const { return (link_type&) head->parent;}
    link_type& leftmost() const { return (link_type&) head->left; }
    link_type& rightmost() const { return (link_type&) head->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 Key& key(link_type x) 
    { return KeyOfValue()value(x); }

    static color_type& color(link_type x) 
    { return (color_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;

private:
    iterator __insert(base_ptr x, base_ptr y, count 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;
        root() = 0;
        leftmost() = header;
        rightmost() = header();
    }

public:
    rb_tree(const Compare& comp = Compare())
    : node_count(0), key_compare(comp) {
        init();
    }

    ~rb_tree() {
        clear();
        put_node(header);
    }
    
    rb_tree<Key, Value, KeyOfValue, Compare, Alloc> &
    operator=(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>&x);

public:
    Compare key_comp() const { return key_compare; }
    iterator begin() { return leftmost(); }
    iterator end() { return header; }
    bool empty() const { return node_count == 0; }
    size_type size() const { return node_count; }
    size_type max_size() const { return size_type(-1); }

public :
    parir<iterator, bool> insert_unique(const value_type&x);
    iterator insert_equal(const value_type&x);
...

};

RB-tree的构造与内存管理

        下面是RB-tree所定义的专属空间配置器rb_tree_node_allocator,每次可恰恰配置一个节点。它所使用的simple_alloc<>是STL中使用的内存分配器(后续补充其定义)

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;
...
};

        先前所列的程序片段也显示了数个节点相关函数如get_node(),put_node(),create_node(),clone_node(),destroy_node()。

        RB-tree的构造方式有两种,一种是以现有的RB-tree复制一个新的RB-tree,另一种是产生一颗空空如也得树,如下所示:

 rb_tree<int, int, identity<int>, less<int> >itree;

        这行程序代码分别指定了节点的键值、实值、大小比较标准...然后调用RB-tree的default constructor:

rb_tree(const Compare& comp = Compare())
: node_count(0), key_compare(comp) { init(); }

        其中init()是实现技巧上的一个关键点:

private:
    void init() {
        header = get_node();
        color(header) = __rb_tree_red;
        root() = 0;
        leftmost() = header;
        rightmost() = header;
    }

          我们知道,树形结构的各种操作,最需要注意的就是边界情况的发生,也就是走到根节点时需要有特殊的处理。为了简化处理,SGI STL特别为根节点再设计一个父节点,名为header,并另其初其初始状态如下图所示;插入节点后,header的left和right,分别指向最小的begin()和最大的元素。

RB-tree的元素操作

        本节主要只谈元素(节点)的插入和搜寻。RB-tree提供两种插入操作:insert_unique()和insert_equal(),前者表示被插入节点的键值(key)在整颗树中必须独一无二,后者表示被插入节点的键值在整颗树中可以重复,因此,无论如何插入都会成功(除非空间不足)。这个两个函数都有数个版本,以下以最简单的版本作为说明对象。注意,虽然只指定实值,但RB-tree一开始即要求用户必须明确设定所谓的KeyOfValue仿函数,因此,从实值中取出键值key是毫无问题的。

元素插入操作insert_equal()

template<class Key, class Value, class KeyOfValue, class Compare, class Alloc> 
typename rb_tree<Key, Value, KeyOfValue, Compare, Allloc>::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);
}

元素插入操作insert_unique()

template<class Key, class Value, class KeyOfValue, class Compare, class Alloc>
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::insert_unque(const Value&v) {
    link_type y = header;
    link_type x = root();
    bool compare = true;
    while(x 1= 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);
    }
}

真正的插入函数__insert()

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;
        if (y == header) {
            root() = z;
            rightmost() = z;
        } else if (y == leftmost()) {
            leftmost() = z;
        }
    } else {
        z = create_node(v);
        right(y) = z;
        if (y == rightmost()) {
            rightmost() = z;
        }
    }
    parent(z) = y;
    left(z) = 0;
    right(z) =0;
    __rb_tree_rebalance(z, header->parent);
    ++node_count;
    return iterator(z);
}

调整RB-tree(旋转及改变颜色)

        任何插入操作,节点插入完毕后,都要进行一次调整操作,将树的状态调整到符合RB-tree的要求。__rb_tree_rebalance()是具备如此能力的一个全局函数:

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) { // 前文提到的状态3
                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);
            }
        }
    } // while 结束
    root->color = _rb_tree_black;
}

        这个属性调整操作,就是前面提到的“由上而下的程序”。从源代码清楚可见,某些时候只需要调整节点颜色,某些时候要做单旋,某些时候要做双旋;某些时候要左旋,某些时候要右旋。下面是左旋和右旋函数

inline void __rb_tree_rotate_left(__rb_tree_node*x, __rb_tree_node_base*&root) {
    __rb_tree_node_base* y = x->right;
    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;

}

元素的搜寻

        RB-tree是一个二叉搜索树,元素的搜寻真是其拿手项目。以下是RB-tree提供的find函数

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>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::find(const Key&k) {
    link_type y = header;
    link_type x = root();
    while(x!=0) {
        if (!key_compare(key(x),k)) {
            y = x;
            x = left(x);
        } else {
            y = x;
            x = right(x);
        }
    }
    iterator j = iterator(j);
    return (j == end() || key_compare(k, key(j.node))) ? end() : j;
}

此处有一个疑问,书中通篇没有提及红黑树中元素删除的处理步骤;后续通过其他途径进行补充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大明__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值