STL源码剖析(十四)关联式容器之set、multiset
文章目录
一、set、multiset简介
关联式容器之所以称为关联式,那是应为每个节点都有key和data
key和data组合到一起叫做value
set是一种比较特殊的关联式容器,应为它没有data,所以key就是value,value就是key
set 和 multiset 的区别就是,set 插入的key不能重复,而 multi_set 可以
二、set、multiset的数据结构
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:
// typedefs:
typedef Key key_type;
typedef Key value_type;
typedef Compare key_compare;
...
private:
typedef rb_tree<key_type, value_type,
identity<value_type>, key_compare, Alloc> rep_type;
rep_type t; // red-black tree representing set
...
};
set里面只是定义了一棵红黑树,下面来看看它指定红黑树的模板参数
首先看看红黑树的模板参数定义
template <class Key, class Value, class KeyOfValue, class Compare,
class Alloc = alloc>
class rb_tree {
...
};
-
Key表示键值
-
Value指的是key加data组合成的结构,对于set来说,由于没有data,所以它依旧是key
-
KeyOfValue是从value取出key的方法,在set中指定了 identity<value_type>,这个是一个仿函数,其作用就是返回自身,如下定义
template <class T> struct identity : public unary_function<T, T> { const T& operator()(const T& x) const { return x; } };
-
Compare是比较键值的方法,set默认采用的是 less<Key>,其定义如下
template <class T> struct less : public binary_function<T, T, bool> { bool operator()(const T& x, const T& y) const { return x < y; } };
搞清楚红黑树的模板参数的意义,那么set的数据结构也就搞清楚了
multi_set 的定义和 set 的定义其实是一样的,如下
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class multiset {
...
private:
typedef rb_tree<key_type, value_type,
identity<value_type>, key_compare, Alloc> rep_type;
rep_type t; // red-black tree representing multiset
...
};
三、set、multiset的迭代器
set 和 multiset 的迭代器都是一样的,如下定义
typedef typename rep_type::const_iterator iterator;
其实它们并没有自己的迭代器,而是直接使用红黑树的迭代器
另外需要注意的一点是,这里使用的是 const_iterator,常量迭代器,是因为红黑树中的key是不允许被改变的
四、set、multiset的操作
set 和 multiset 的操作主要区别在于插入操作,所以这里只将插入操作有所区别,其他操作都是通用的
4.1 构造函数
默认构造
set() : t(Compare()) {}
初始化其中的红黑树
拷贝构造
set(const set<Key, Compare, Alloc>& x) : t(x.t) {}
拷贝其中的红黑树
4.2 析构函数
set没有定义析构函数,当set内存被释放时,红黑树也会自动被析构释放
4.3 插入元素
set 的 insert
typedef pair<iterator, bool> pair_iterator_bool;
pair<iterator,bool> insert(const value_type& x) {
pair<typename rep_type::iterator, bool> p = t.insert_unique(x);
return pair<iterator, bool>(p.first, p.second);
}
set 的 insert 调用的是红黑树的 insert_unique,它不支持键值重复
返回值是一个对组,包含一个指向插入节点的迭代器还有结果
multiset 的 insert
iterator insert(const value_type& x) {
return t.insert_equal(x);
}
multiset 调用的是 insert_equal,它支持键值重复
放回值是指向插入节点的迭代器,因为允许键值重复,所以插入一定成功,因此没有返回插入结果
4.4 删除元素
size_type erase(const key_type& x) {
return t.erase(x);
}
调用红黑树的erase
4.5 其他操作
begin
iterator begin() const { return t.begin(); }
end
iterator end() const { return t.end(); }
find
iterator find(const key_type& x) const { return t.find(x); }
可以发现,set 和 multiset 的操作基本上都是通过底层的红黑树实现的