容器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.