1. set和map的底层结构: 红黑树(rb_tree)
需要注意的是, 红黑树的结构是允许我们用iterator改变元素值的, 但是不应该这么做, 因为红黑树会自动排序, 如果我们改变值, 就会破坏红黑树的结构. 后面会看到, set和map把这种自由度给限制了.
下面是GNU2.9的rb_tree代码, 可以看到, 模板需要传入key, value, keyofvalue, compare, alloc
5个模板参数, 具体参数意义就不说了…
类里面只有三个成员, 分别是node_count
, header
, 以及key_compare(应该是个仿函数)
, 所以假设size_type
为4个字节, header是指针类型4个字节, 仿函数属于一个类, 大小为1字节, 一共9个字节, 按照内存字节对齐, 一共分配12个字节.
下面用一个例子来说明, 左上角是用rb_tree来声明的类, 按照对应关系一一对应.
其中identity
函数是给一个值, 返回它自己; less则是标准库的仿函数.
要注意的是, value
这个参数, 是key+data
的合成.
在GUN4.9以上, rb_tree的名字稍微改了一下:
//头文件包含<set>或者<map>即可
void test01(){
//测试rb_tree
_Rb_tree<int, int, _Identity<int>, less<int>> itree;
cout << itree.empty() << endl; //1
cout << itree.size() << endl; //0
itree._M_insert_unique(3);
itree._M_insert_unique(8);
itree._M_insert_unique(5);
itree._M_insert_unique(9);
itree._M_insert_unique(13);
itree._M_insert_unique(5);//unique不插入重复的
cout << itree.empty() << endl; //0
cout << itree.size() << endl; // 5
cout << itree.count(5) << endl; //1
itree._M_insert_equal(5);
itree._M_insert_equal(5);
cout << itree.size() << endl; //7
cout << itree.count(5) << endl; // 3
}
2. set, multiset
3. map, multimap
标准库代码: