C++ STL和泛型编程(二)---- rb_tree
一、rb_tree结构
其是平衡二分搜索树中经常被使用的一种:
其排列规则【左子树上所有结点的值均小于或等于它的根结点的值,右子树上所有结点的值均大于或等于它的根结点的值,左、右子树也分别为二叉排序树】有利于search和insert,并保持适度平衡而无任何节点过深。其遍历顺序是先左端子树节点,再根节点再右子树节点即左中右、左中右。所以iterator begin()指向最左端的左子树节点,iterator end()指向最右端的右子树节点。
一般不使用rb_tree的iterator改变其value中的key【作为元素排列规则的参数】,但可以修改value中的data,而为map和set做底部支持。(如map中允许data被改变,key不允许改变;而set中因为key和value是同一个,所以不允许改变)
rb_tree的两种insertion操作:
insert_unique(),表示所插入的节点key是唯一的,否则安插失败;
insert_equal(),表示所插入的节点key可以重复。
二、底层代码实现
template<class Key, class Value, class KeyOfValue, class Compare, class Alloc = alloc>
class rb_tree{
protected:
typedef __rb_tree_node<Value> rb_tree_node;
...
public:
typedef rb_tree_node* link_type;
...
protected:
size_type node_count; // rb_tree节点数量,unsigned int型
link_type header; // 由上看知其是指针类型
Compare key_compare; // key的大小比较准则;应是个函数对象(大小为0,因为其本身并没有数据)
// 但无论在何种编译器,对于大小为0的class其创造出来的对象大小为1。因而key_compare大小实际为1)
...
}
class Key 表示要告诉模板Key的类型
class Value 表示要告诉模板Value(Key + Data)是什么类型
class KeyOfValue 表示要告诉模板在Value里面如何取得Key
class Compare 表示要告诉模板关于Key的比较大小的准则,其应是个function object
class Alloc = alloc 表示分配器是默认值
由上知,其变量有3个:node_count、header、key_compare,所以大小为4+4+1=9。而9得往4的倍数上调,所以最终9->12。
另外rb_tree中,header是空的,类似于list容器中的最后一个空的结点。
由图知,第三个模板参数identity<int>是个仿函数类型其继承的父类unary_function是个adaptor,且是gnu C独有的。另外因为其内部是operator(),则其创建出来对象如identity c时,其对象调用()即c.()类似于函数的调用,因而称为仿函数类型。而实现的操作表示传入什么就传出什么,则这里的KeyOfVlaue表示的操作为元素里面放3经过identity传回来就是3,3就是其Key即借由仿函数identity类告诉 rb_tree 如何在value中找出key。
第四个模板参数也类似。
- G4.9的实现
感觉是否实心的应该为空心的菱形,因为实心的菱形表示的是复合的关系,而空心的菱形才是委托关系【即指针包含的复合关系】。
这里_Rb_tree<…>与_Rb_tree_impl<…>是一种很有名的handle/body(pImpl) 的关系。
而对于G4.9中_Rb_tree的大小知,其最终的变量是 _M_left\ _M_right\ _M_parent(_Base_ptr类型即指针类型),_M_color(_Rb_tree_color类型即enum枚举类型,大小为12),因而其在G4.9下的大小为24。