STL源码剖析(十五)关联式容器之map、multimap
文章目录
map 和 multimap 每个元素都是一个对组,有 key 也有 dada
map 和 multimap 的主要区别是,map 键值不可以重复,multimap 可以
一、map、multimap的数据结构
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map {
public:
typedef Key key_type;
typedef T data_type;
typedef pair<const Key, T> value_type;
...
private:
typedef rb_tree<key_type, value_type,
select1st<value_type>, key_compare, Alloc> rep_type;
rep_type t; // red-black tree representing map
...
};
map 的成员函数只有一棵红黑树,基本上所有的操作依赖于它,要搞懂 map 的数据结构,首先需要先弄懂指定给红黑树的这些模板参数
红黑树的模板参数定义如下
template <class Key, class Value, class KeyOfValue, class Compare,
class Alloc = alloc>
class rb_tree {
...
};
-
Key表示键值,在 map 的模板参数指定
-
Vlue表示键值加上数据,在 map 中这样定义 typedef pair<const Key, T> value_type,其中的 pair 为对组,负责将两个类型结合成一个类型,其定义如下
template <class T1, class T2> struct pair { typedef T1 first_type; typedef T2 second_type; T1 first; T2 second; pair(const T1& a, const T2& b) : first(a), second(b) {} };
first 获取第一个元素,second 获取第二个元素
仔细看可以 pair 指定的 Key 为 const Key,表示 key 值是不可以被修改的
-
KeyOfValue 是从 value 中获取 key 的仿函数,在 map 中定义如下,select1st<value_type>,其实就是取对组的 first 成员,定义如下
template <class Pair> struct select1st : public unary_function<Pair, typename Pair::first_type> { const typename Pair::first_type& operator()(const Pair& x) const { return x.first; } };
-
Compare 用于键值比较的仿函数,map 默认指定的是 less<Key>
到这里,map 的数组结构也应该清楚了,multimap 的数据结构其实是和 map 一样的,这里就不列出了
二、map、multimap的迭代器
map 和 multimap 的迭代器都是一样的,都是直接取出红黑树的迭代器,如下
typedef rb_tree<key_type, value_type,
select1st<value_type>, key_compare, Alloc> rep_type;
typedef typename rep_type::iterator iterator;
如果要通过迭代器修改某个节点的数据,需要下面这样做
it->second = xxx;
三、map、multimap的操作
map 和 multimap 的操作基本相同,都是调用红黑树,唯一的区别就是插入操作调用红黑树不同的插入函数
3.1 构造函数
默认构造
map() : t(Compare()) {}
初始化红黑树
拷贝构造
map(const map<Key, T, Compare, Alloc>& x) : t(x.t) {}
拷贝红黑树
3.2 析构函数
map 和 multimap 没有定义析构函数,当释放内存的时候,其中的红黑树会自动被析构释放掉
3.3 插入元素
map 插入元素
pair<iterator,bool> insert(const value_type& x) { return t.insert_unique(x); }
调用的是红黑树的 insert_unique 方法,其不允许键值重复
multimap 插入元素
iterator insert(const value_type& x) { return t.insert_equal(x); }
调用的是红黑树的 insert_equal 方法,其运行键值重复
3.4 删除元素
size_type erase(const key_type& x) { return t.erase(x); }
通过红黑树的 erase 方法删除
3.5 其他操作
begin
iterator begin() { return t.begin(); }
end
iterator end() { return t.end(); }
find
根据 key 查找指定节点,放回对应的迭代器
iterator find(const key_type& x) { return t.find(x); }
**lower_bound **
查找大于等于指定 key 的节点
iterator lower_bound(const key_type& x) {return t.lower_bound(x); }
**upper_bound **
查找大于指定 key 的节点
iterator upper_bound(const key_type& x) {return t.upper_bound(x); }