STL中_Rb_tree的探索

我们知道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}

原文地址:https://www.cnblogs.com/sandychn/p/12334194.html

时间: 2024-08-29 19:00:58

STL中_Rb_tree的探索的相关文章

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

STL中vector什么时候会自动分配内存,又是怎么分配的呢? 环境:Linux  CentOS 5.2 1.代码 #include <vector> #include <stdio.h> using namespace std; int main() { vector<int> x_vec; printf("data size : [%3d], mem size : [%3d]\n", x_vec.size(), x_vec.capacity())

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

原文  http://blog.csdn.net/iicy266/article/details/11906189 map是用来存放<key, value>键值对的数据结构,可以很方便快速的根据key查到相应的value.假如存储学生和其成绩(假定不存在重名,当然可以对重名加以区分),我们用map来进行存储就是个不错的选择. 我们这样定义,map<string, int>,其中学生姓名用string类型,作为Key:该学生的成绩用int类型,作为value.这样一来,我们可以根据学

STL中的nth_element()方法的使用

STL中的nth_element()方法的使用 通过调用nth_element(start, start+n, end) 方法可以使第n大元素处于第n位置(从0开始,其位置是下标为 n的元素),并且比这个元素小的元素都排在这个元素之前,比这个元素大的元素都排在这个元素之后,但不能保证他们是有序的,下面是这个方法的具体使用方法. 1 #include <iostream> 2 3 #include <algorithm> 4 5 #include <functional>

STL中的Vector相关用法

STL中的Vector相关用法 标准库vector类型使用需要的头文件:#include <vector>. vector 是一个类模板,不是一种数据类型,vector<int>是一种数据类型. Vector的存储空间是连续的,list不是连续存储的. 1. 定义和初始化 vector< typeName > v1; //默认v1为空,故下面的赋值是错误的v1[0]=5;//v2是v1的一个副本,若v1.size()>v2.size()则赋值后v2.size()被

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

http://blog.csdn.net/sunshinewave/article/details/8068326 1.关于set C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作.vector封装数组,list封装了链表,map和set封装了二叉树等,在封装这些数据结构的时候,STL按照程序员的使用习惯,以成员函数方式提供的常用操作,如:插入.排序.删除.

STL中map的用法

map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道.这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处. 下面举例说明什么是一对一的数据映射.比如一个班级中,每个学生的学号跟他的姓名就存在着一一

stl中char 与wchar 的转换

学习记录: stl中 字符串 str自然对应的是string 宽字符串wchar 对应的是wstring 宽字符串占用两个字节 两者的转换有三种办法 1 windows 的api转换函数WideCharToMultiByte()与MultiByteToWideChar(). 不适合跨平台使用. 2 ATL中CA2W类与CW2A类.或者使用A2W宏与W2A宏.稍显累赘和麻烦 3 使用CRT库的函数 函数和使用方法见下列代码 #include <string> #include <iostr

c++ STL中的vector与list为什么没有提供find操作?

map里有,set里也有,vector,list没有,太不公平了吧. 其实应该考虑为什么map,set里有find操作. include<algorithm>里有通用的find操作,通用的find内部是从begin到end进行一次遍历,复杂度是O(n). 通过iterator从begin到end遍历map与set时,得到的结果是按key排序的结果,而不是插入时的顺序(所以这两个容器没有push_back操作), 其实,insert到map与set中的元素会被组织到一颗红黑树上,红黑树是一颗平衡

Binary Search 的递归与迭代实现及STL中的搜索相关内容

与排序算法不同,搜索算法是比较统一的,常用的搜索除hash外仅有两种,包括不需要排序的线性搜索和需要排序的binary search. 首先介绍一下binary search,其原理很直接,不断地选取有序数组的组中值,比较组中值与目标的大小,继续搜索目标所在的一半,直到找到目标,递归算法可以很直观的表现这个描述: int binarySearchRecursive(int A[], int low, int high, int key) { if (low > high) return -1;