- map
map的特性是,所有元素都会根据元素的键值自动被排序。map的所有元素都是pair,同时拥有实值(value)和键值(key)。pair的第一元素被视为键值,第二元素被视为实值。map不允许两个元素拥有相同的键值。
我们不能通过map的迭代器修改map的键值,但是可以通过迭代器修改map的实值,因为红黑树的底层只提供了插入和删除操作的自平衡,并没有提供这种修改键值的自平衡,所以是不能通过迭代器修改键值的。
map拥有list相同的某些性质:当客户端对她进行元素新增操作或删除操作的时候,操作之前的所有迭代器,在操作完成之后都依然有效。当然,被删除的那个元素的迭代器必然是个例外。
标准的STL map 以红黑树作为底层的实现机制。
map的部分源码如下:
template <typename Key, typename T,typename Compare = less<Key>, typename Alloc = alloc>
//Compare缺省的情况使用递增排序
class map{
public:
//typedefs:
typedef Key key_type; //键值类型
typedef T data_type; //数值类型
typedef pair<const Key, T> value_type; //元素类型
typedef Compare key_compare;//键值比较函数
//以下定义一个functor,其作用就是调用“元素比较函数”
class value_compare: public binary_function<value_type, value_type, bool>{
friend class map<Key, T, Compare, Alloc>;
protected:
Compare comp;
value_compare (Compare c):comp(c){}
public:
bool operator()(const value_type& x, const value_type& y) const {
return comp(x.first, y.first);}
};
private:
typedef rb_tree<key_type, value_type, select1st<value_type>, key_compare, Alloc> rep_type;
rep_type t;//采用红黑树来实现map
public:
typedef typename rep_type::pointer pointer;
typedef typename rep_type::const_pointer const_pointer;
typedef typename rep_type::reference reference;
typedef typename rep_type::const_reference const_reference;
typedef typename rep_type::iterator iterator;
//注意上一行Iterator并不像set一样是红黑树的const_iterator,因为map允许通过迭代器修改实值
typedef typename rep_type::const_iterator const_iterator;
typedef typename rep_type::reverse_iterator reverse_iterator;
typedef typename rep_type::const_reverse_iterator const_reverse_iterator;
typedef typename rep_type::size_type size_type;
typedef typename rep_type::difference_type difference_type;
//下面几个是map的构造函数,注意,map一定使用RB-tree的insert_unique()而非insert_equal()
//multimap才使用红黑树的insert_equal(),因为map不允许相同键值存在,而multimap允许
mqp():t(Compare()){}
template<class InputIterator>
map(InputIterator first, InputIterator last):t(Compare()){t.inser_unique(first, last);}
template<class InputIterator>
map(InputIterator first, InputIterator last, const Compare& comp):t(comp){t.inser_unique(first, last);}
map(const set<Key, Compare, Alloc>& x):t(x.t){}
//赋值运算符
map<Key, Compare, Alloc>& operator=(const set<Key, Compare, Alloc>& x){
t = x.t;
return *this;
}
//下面的操作,红黑树已经提供,map只要调用即可
iterator begin() const {return t.begin();}//升序排序时指向最xiao节点
iterator end() const {return end();}//注意这个指向的是树的header,头结点的父节点(小技巧)
reverse_iterator rbegin() const {return t.rbegin();}//升序排序时指向最da节点
reverse_iterator rend() const {return t.rend();}
bool empty() const {return t.empty();}
size_type size() const {return t.size();}
T& operator[](const key_type& k){
return (*((insert(value_type(k,T()))).first)).second;
}
//注意下面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);//红黑树中insert_unique返回pair
return pair<iterator, bool>(p.first, p.second);
}
template <typename InputIterator>
void insert(InputIterator first, InputIterator last){
t.insert_unique(first, last);
}
void erase(iterator position){
t.erase(position);
}
void erase(iterator first, iterator last){
t.erase(first, last);
}
size_type erase(const key_type& x){
return t.erase(x);
}
}
map所提供的函数简介:
- pair<iterator, bool> insert(const value_type& x)
这个函数底部调用的是insert_unique,返回的是一个pair,pair的第一个元素是插入的节点的迭代器,第二个元素是是否插入成功。注意map的value_type是一个pair
- begin(),rbegin(), end(),rend()
begin和end是正向迭代器,其他的两个是反向迭代器。假设红黑树是递增的(左子树的节点key < 根节点key < 右子树的节点key),这是begin()返回最小元素的迭代器而rbegin()返回最大元素的迭代器。end()和rend()都是header节点的迭代器。(header是STL实现红黑树时的小技巧,header的父亲指针指向root,header的左指针指向以root为根节点的最小元素,header的右指针指向以root为根节点的最大元素,root的父节点指向header)
- void insert(InputIterator first, InputIterator last)
这个函数的参数盛放是插入元素的容器的迭代器的开始位置和结束位置,注意返回值是void。注意容器里面放的应该是pair
- void erase(iterator position)
函数参数是要删除的元素的迭代器
- void erase(iterator first, iterator last)
函数第一个参数是要删除的元素段的key最小元素的迭代器,第二个参数是要删除元素段的key最大元素的迭代器
- size_type erase(const key_type& x)
函数参数是删除元素的key值
- iterator find(const key_type& x)
返回x的迭代器
- size_type count(const key_type& x)
返回节点key值为x的节点个数
- T& operator[](const key_type & k)
注意函数的返回值是引用,可以使用mymap[key]的方式读取,key所对应的value。并且可以使用mymap[key] = myvalue的方式进行插入(注意运算符底层是调用的insert函数,并且返回的是引用,所以允许通过这种方式进行赋值)。
- multimap
multimap的特性及用法与map完全相同,唯一的差别在于multimap允许键值重复,因此它的插入操作采用的红黑树的insert_equal()而不是insert_unique()。注意insert_unique的返回值是pair前面已经介绍了,insert_equal的返回值是插入节点的Iterator,注意使用下面函数和map返回值的区别:
//返回值和map不一样,map中的value_type是pair
iterator insert(const value_type& x){
return t.insert_equal(x);
}