我们知道STL中我们常用的setmultisetmapmultimap都是基于红黑树。本文介绍了它们的在STL中的底层数据结构_Rb_tree的直接用法与部分函数。难点主要是_Rb_tree的各个参数的确定。

特别注意在如下代码的Selector类用于从Node中选出用于排序的key值,这个仿函数必须返回const int&而不能是int,否则less<int>::operator(const int&, const int&)会抛出segmentation fault。由于源码中逻辑比较复杂,但是可以观察到内部涉及这方面的地方经常使用到指针。所以可以推测是因为引用了已经释放的局部变量所以才抛出的segmentation fault。一开始写成int,看了很多源码才发现是这个原因,一定要注意。

接下来是样例代码,里面都有注释了。

#include <iostream>
#include <iomanip> // 原则上不要直接引用这个头文件,这里只是为了测试
#include <bits/stl_tree.h> using namespace std; struct Node {
int first, second;
Node(int _first, int _second) : first(_first), second(_second){}; friend ostream& operator<<(ostream& outs, const Node& node) {
outs << '{' << node.first << ',' << node.second << '}';
return outs;
}
}; template <class T>
struct Selector {
// MUST return const int&, not int.
// if return int, segmentation fault will occur.
// I have spent much time because of this.
const int& operator()(const T& obj) const {
return obj.first;
}
}; int main() {
// _Rb_tree: red-black tree in STL.
using tree_type = _Rb_tree<int, Node, Selector<Node>, less<int>>;
using iterator_type = tree_type::iterator;
using result_pair_type = pair<tree_type::iterator, bool>;
tree_type tree; // 插入元素Node(1, 2)
result_pair_type res = tree._M_insert_unique(Node(1, 2));
cout << "insert address = " << res.first._M_node << endl;
cout << "insert result = " << boolalpha << res.second << endl; // true iterator_type it = tree.begin();
cout << "begin address = " << it._M_node << endl; it = tree.find(1);
cout << "address = " << it._M_node << ", value = " << *it << endl; // 再插入元素Node(1, 2)但是因为调用的是insert_unique
// 它不会添加重复值,所以插入会被拒绝
res = tree._M_insert_unique(Node(1, 2));
cout << "insert result = " << boolalpha << res.second << endl; // false // 再插入元素Node(1, 2)但这次调用insert_equal
// multiset和multimap就是利用这个函数来插入重复值
// 也就是这个函数允许重复值,所以插入成功
tree._M_insert_equal(Node(1, 3));
cout << "size = " << tree.size() << endl; // 大小就变为2 pair<iterator_type, iterator_type> result = tree.equal_range(1);
for (iterator_type ite = result.first; ite != result.second; ++ite) {
cout << "address = " << ite._M_node << ", value = " << *ite << endl;
} return 0;
}

程序的输出为(内存地址不定):

insert address = 0xf91be0
insert result = true
begin address = 0xf91be0
address = 0xf91be0, value = {1,2}
insert result = false
size = 2
address = 0xf91be0, value = {1,2}
address = 0xf91c10, value = {1,3}

STL中_Rb_tree的探索的更多相关文章

  1. C++的STL中vector内存分配方法的简单探索

    STL中vector什么时候会自动分配内存,又是怎么分配的呢? 环境:Linux  CentOS 5.2 1.代码 #include <vector> #include <stdio ...

  2. STL中的set容器的一点总结

    1.关于set C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构 ...

  3. STL中的next_permutation

    给定一个数组a[N],求下一个数组. 2 1 3 4 2 1 4 3 2 3 1 4 2 3 4 1 ..... 在STL中就有这个函数: 1.参数是(数组的第一个元素,数组的末尾),注意这是前闭后开 ...

  4. 3.2 STL中的函数对象类模板

    *: STL中有一些函数对象类模板,如下所示: 1)例如要求两个double类型的x 和y 的积,可以: multiplies<double>()(x,y); 该表达式的值就是x*y的值. ...

  5. C++的模板特化 和 STL中iterator_traits模板的偏特化

    C++中有类模板和函数模板,它们的定义如下所示: 类模板: template<class T1,class T2> class C { //... }; 函数模板: template< ...

  6. C++ STL中vector(向量容器)使用简单介绍

    原文:http://www.seacha.com/article.php/knowledge/cbase/2013/0903/2205.html C++ vector(向量容器)是一个线性顺序结构.相 ...

  7. 深入了解STL中set与hash_set,hash表基础

    一,set和hash_set简介 在STL中,set是以红黑树(RB-Tree)作为底层数据结构的,hash_set是以哈希表(Hash table)作为底层数据结构的.set可以在时间复杂度为O(l ...

  8. 【转】 STL中的set容器的一点总结

    1.关于set C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构 ...

  9. C++ STL中Map的按Key排序和按Value排序

    map是用来存放<key, value>键值对的数据结构,可以很方便快速的根据key查到相应的value.假如存储学生和其成绩(假定不存在重名,当然可以对重名加以区 分),我们用map来进 ...

随机推荐

  1. 一起了解 .Net Foundation 项目 No.5

    .Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. Couchbase Lit ...

  2. 详解Net Core Web Api项目与在NginX下发布

    前言 本文将介绍Net Core的一些基础知识和如何NginX下发布Net Core的WebApi项目. 测试环境 操作系统:windows 10 开发工具:visual studio 2019 框架 ...

  3. Flutter Widgets 之 FutureBuilder

    注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 展示异步任务状态 当有一个Future(异步)任务需要展示 ...

  4. python随用随学20200118-函数的高级特性

    高阶函数 话说当年C语言和Java里好像都有这么个东西...忘了 一句话说就是函数名本身就是一个引用. 可以作为变量传递. 一个简单的例子: def power_demo(x):  return x* ...

  5. Properties(hashtable的子类)

    Properties: Properties是hashtable的子类(在java.util包中).该集合的特点:可以用于键值对形式的配置文件,且不允许Key重复,若有重复的,后者会覆盖前者. 也就是 ...

  6. RX.js6变化

    RX.js变化 RxJS 6主要用于Angular应用程序,从Angular 6开始,它是一个强制依赖. 与RxJS版本5相比,RxJS 6(或更高版本)引入了两个重要更改: 1. import的导入 ...

  7. Android Gradle报错 (Error:No such property: GradleVersion for class: JetGradlePlugin) 的原因与解决

    Error:No such property: GradleVersion for class: JetGradlePlugin 错误原因:IDE 版本(GradlePlugin)和 Gradle 版 ...

  8. CentOS、Ubuntu的安装

    Linux使用最广泛的2个发行版:CentOS.Ubuntu. CentOS安全性高,常用作企业的服务器,Ubuntu常用作个人桌面. 常见的虚拟机有2个: VM VirtualBox,这个是Orac ...

  9. Bash脚本编程学习笔记07:循环结构体

    本篇中涉及到算术运算,使用了$[]这种我未在官方手册中见到的用法,但是确实可用的,在此前的博文<Bash脚本编程学习笔记03:算术运算>中我有说明不要使用,不过自己忘记了.大家还是尽量使用 ...

  10. 防止或减少过拟合的方式(二)——Dropout

    当进行模型训练的时候,往往可能错过模型的最佳临界点,即当达到最大精度的时候再进行训练,测试集的精度会下降,这时候就会出现过拟合,如果能在其临界点处提前终止训练,就能得到表达力较强的模型,从而也避免了过 ...