STL关联式容器map、set、multimap、multiset,绝大部分操作如插入、修改、删除、搜索,都是由其内含的红黑树来完成的。
红黑树数据结构和算法的讲解见:
数据结构与算法:红黑树讲解
我下面会总结 STL中rb_tree怎么实现的。
首先,rb_tree是红黑树,所以需要定义红色和黑色。
然后需要定义 红黑树的节点。
_Rb_tree_node_base定义了红黑树的节点类,从类中可以看出一个节点有颜色、父指针、左孩子指针、右孩子指针4个属性。然后定义了几个函数,可以找到以这个节点为根节点的红黑树的最大节点和最小节点。
_Rb_tree_node继承了_Rb_tree_node_base,在基础上添加了 一个数据类型,同时对C++11之前和之后值存储在
了解
C++11之前(
__cplusplus < 201103L
):值直接存储在节点内部,作为_Val _M_value_field
。访问函数_M_valptr()
返回这个值的指针,使用std::__addressof(_M_value_field)
来获取其地址。C++11及以后:值存储在
__aligned_buffer<_Val> _M_storage
内部。这样做很可能是为了确保数据的适当对齐。访问函数_M_valptr()
通过调用_M_storage._M_ptr()
返回值的指针,这个函数可能处理对齐问题并返回实际值的指针。
__aligned_buffer
是一个模板结构,它提供了一种机制来按照类型_Val
的对齐要求分配内存。在C++11及更高版本中,对齐是一个重要的概念,因为它影响数据的访问速度和效率。不正确的数据对齐可能导致性能下降或者在某些平台上引起错误。
_M_storage
使用__aligned_buffer
为类型_Val
的对象提供存储空间。这种方式使得即使在栈上分配时,对象也能保证按照其对齐要求被正确地存储。这对于需要特定对齐要求的类型特别有用,比如SIMD类型(如SSE和AVX指令集中使用的类型)或者其他需要特定对齐以优化硬件性能的数据类型。在C++11之前,没有标准的方法来指定或查询类型的对齐要求,因此
_M_storage
的使用也体现了对于老版本C++的向后兼容性考虑。在C++11及以后版本中,alignof
和alignas
关键字引入了对齐的标准支持,允许开发者更精确地控制数据的对齐方式。__aligned_buffer<_Val> _M_storage
是一种高级技术,用于确保类型_Val
的对象在红黑树节点内部以正确的对齐方式存储,这对于保持数据结构的性能和正确性是非常重要的。
rb_tree的迭代器
rb_tree迭代器定义了5个STL迭代器必须定义的类型。
然后重载了一些运算符。
重点要看一下__rb_tree_iterator 的 operator++ 跟 operator--。它们分别调用了实际是调用__rb_tree_base_iterator的increment跟decrement。
迭代器前移/后移的时候会按key的顺序找到下一个/上一个结点。
rb_tree实现与普通的红黑树类似。
insert_equal插入元素,允许元素重复;insert_unique插入元素,不允许元素重复。
insert_equal允许RBTree中存在相同的节点,进行插入时,小于当前节点则向左走;等于或等于则向右走;如果有相同的元素,则插在相同元素的右侧,比如9的右子节点有一个10,则在插入10就插入在这个10的右子节点。
inert_unique不允许RBTree中存在相同的节点,在找到插入位置后,如果插入位置的父亲节点的值与待插入节点(插入一定插在一个空子树的位置)相同,则不插入。
红黑树存储值的类型是value_type,value_type定义是
typedef pair<const Key, T> value_type; //value_type的定义
pair存储键值对,第一个元素是Key,是const类型,不可改变的。