关联式容器

点点圈 提交于 2020-02-08 17:04:57

容器rb_tree

Red-Black tree(红黑树)是平衡二叉搜索树(balanaced binary search tree)中常被使用的一种。平衡二叉搜索树的特征:排列规则有利于search和insert,并保持适度平衡——无任何节点过深。

rb_tree提供遍历操作及iterators。按正常规则(++ite)遍历,便能获得排序状态。

我们不应使用rb_tree的iterators改变元素值(因为元素有其排列规则)。编程层面并未阻值此事。如此设计是正确的,因为rb_tree即将为set和map服务(作为其底部支撑),而map允许元素的data被改变,只有元素的key才是不可被改变的。

rb_tree提供两种insert操作:insert_unique()和insert_equal()前者表示节点的key一定在整个tree中独一无二,否则安装失败,后者表示节点的key可以重复。

rb_tree的实现代码

namespace rb_tree{

    template <class Key, //键
              class Value, //key与data组合称为data
              class KeyOfValue, //如何从value中取出data
              class Compare,  //key之间的比较方法
              class Alloc = alloc> //分配器
    class rb_tree {
    protected:
        typedef __rb_tree_node<Value> rb_tree_node;
    public:
        typedef rb_tree_node* link_type;
    protected:
        //RB_tree只以三个资料表现它自己
        size_type node_count; //rb_tree的大小 4
        link_type header;  //大小为4
        Compare key_compaer; //key的比较规则,应该是仿函数对象 大小为1

    };
};

rb_tree的结构

rb_tree的noede结构

_M_color: _Rb_tree_color //节点颜色 枚举类型
_M_parent: _Base_Ptr //指向父节点的指针
_M_right: _Base_Ptr //指向右孩子的指针
_M_right: _Base_ptr //指向左孩子的指针

所以一共是16个字节

set/multiset

set的定义

set/multiset是以rb-tree为底层结构,因此元素有自动排序的性质。排序的依据是key,而set/multiset元素的key和value合二为一。

set/multiset提供遍历操作,以及iterators.按照正常操作就可以获得排序状态。

我们无法使用set/multiset的iterators改变元素的值(因为key有其严谨的排序规则)。set/multiset的iterator是其改变底部RB-tree的const iterator,就是为了禁止user对元素赋值。

set元素的key独一无二,因此其insert()用的是rb_tree的insert_unique();
multiset的key可以重复,因此insert()用的是rb_tree的insert_equal();

set的代码实现

namespace set_test {
    template <class Key,
              class Compare = less<Key>,
              class Alloc = alloc>
    class set {
    public:
        //typedefs 
        typedef Key key_type;
        typedef Key value_type;
        typedef Compare key_compare;
        typedef Compare value_compare;
    private:
        typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc>rep_type;
        rep_type t;
    public:
        typedef typename rep_type::const_iterator iterator;
    };
}

set的操作分析

当你拿set的迭代器时,拿到的是const_iterator,而且是rb_tree的迭代器,所以set不允许通过迭代器改变key.
set的所有操作都是通过调用底部的rb_tree来完成的,和stack和queue一样(调用deque)

set内部数据结构图

map/multimap

map的性质

map/multimap是以rb_tree为底层结构,因此有元素自动排序特性,排序的依据是key.
map/multimap提供遍历操作以及iterators,按正常规则遍历,便能获得排序状态。
我们无法使用map/multimap的iterators改变元素的key,但可以用它来改变元素的data,因此map/multimap内部自动将user指定的 key type设为const,如此便能禁止user对元素的key赋值。

map元素的key必须独一无二,因此insert使用的是rb_tree的insert_unique()
multimap的key是可以重复的,因此insert使用的是rb_tree的insert_equal()

map的实现

#pragma once
template <class Key, class T,class Compare = less<key>,class Alloc = alloc>
class map {
public:
    typedef Key key_type;
    typedef T data_type;
    typedef T mapped_type;
    typedef pair<const Key, T> value_type;
    typedef Compare key_compare;
private:
    typedef rb_tree<key_type, value_type,
        selectlst<value_type>, key_compare, Alloc> rep_type;
    rep_type t;
public:
    typedef typename rep_type::iterator iterator;
};

map的内部数据结构图

map数据结构的组成

map<int,string>imap;
当我们输入上述代码时:
pair<const key,T>value_type; 将传入的两个参数合并成为一个map,且pair的第一个元素为const.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!