在本小节中,我们将分析map
容器,它与set
最大的不同就是,它是key-value
型的,而set
的key
和value
是同一个。map
和set
底层都由红黑树实现,map
上存储的都是pair
,即键值对,存储到红黑树中时,排序依据的就是pair
的第一个元素。
之前提到在set
中,不允许更改元素的值,而在map
中,key
值同样不允许修改,但是value
可以修改,因为value
不涉及到map
整体内部结构的改变。
接下来,我们进入到map
的源码中。
map
的实现#ifndef __STL_LIMITED_DEFAULT_TEMPLATES
template <class Key, class T, class Compare = less, class Alloc = alloc>
#else
template <class Key, class T, class Compare, class Alloc = alloc>
#endif
class map {
public:
// typedefs:
/* 一些类型的声明
* 可以看到value_type是pair
* 注意是const key,不可修改
*/
typedef Key key_type;
typedef T data_type;
typedef T mapped_type;
typedef pair<const Key, T> value_type;
typedef Compare key_compare;
//仿函数,它的作用是调用元素比较大小标准函数
class value_compare
: public binary_functionbool> {
friend class map ;
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_compare, Alloc> rep_type;
rep_type t; // red-black tree representing 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;
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;
// allocation/deallocation
//设置默认的或者自己传入的大小比较标准
map() : t(Compare()) {}
explicit map(const Compare& comp) : t(comp) {}
/* 范围构造时,调用insert_unique
* 下面根据条件编译区分不同的情况,有很多的重载版本
*/
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
map(InputIterator first, InputIterator last)
: t(Compare()) { t.insert_unique(first, last); }
template <class InputIterator>
map(InputIterator first, InputIterator last, const Compare& comp)
: t(comp) { t.insert_unique(first, last); }
#else
map(const value_type* first, const value_type* last)
: t(Compare()) { t.insert_unique(first, last); }
map(const value_type* first, const value_type* last, const Compare& comp)
: t(comp) { t.insert_unique(first, last); }
map(const_iterator first, const_iterator last)
: t(Compare()) { t.insert_unique(first, last); }
map(const_iterator first, const_iterator last, const Compare& comp)
: t(comp) { t.insert_unique(first, last); }
#endif /* __STL_MEMBER_TEMPLATES */
/* 拷贝构造函数
* 直接对红黑树进行复制就行了
*/
map(const map & x) : t(x.t) {}
map & operator=(const map & x)
{
t = x.t;
return *this;
}
//基本上都是调用红黑树提供的接口
// accessors:
key_compare key_comp() const { return t.key_comp(); }
value_compare value_comp() const { return value_compare(t.key_comp()); }
iterator begin() { return t.begin(); }
const_iterator begin() const { return t.begin(); }
iterator end() { return t.end(); }
const_iterator end() const { return t.end(); }
reverse_iterator rbegin() { return t.rbegin(); }
const_reverse_iterator rbegin() const { return t.rbegin(); }
reverse_iterator rend() { return t.rend(); }
const_reverse_iterator rend() const { return t.rend(); }
bool empty() const { return t.empty(); }
size_type size() const { return t.size(); }
size_type max_size() const { return t.max_size(); }
/* 重载[]操作符,这是set中没有的
* *((insert(value_type(k, T()))).first).second 这个表达式有点复杂,传入值是key
* insert的返回值是pair,pair的第一个元素代表指向插入元素的迭代器,而第二元素代表插入是否成功
* 那我们来分析这个表达式,insert调用之后访问返回值的第一个元素,即指向插入元素的迭代器,并使用*取值
* 此时就获取到了存着key-value的pair,然后访问其第二个成员(second),返回传入的key对应的value。
*/
T& operator[](const key_type& k) {
return (*((insert(value_type(k, T()))).first)).second;
}
void swap(map & x) { t.swap(x.t); }
// insert/erase
pairbool> insert(const value_type& x) { return t.insert_unique(x); }
iterator insert(iterator position, const value_type& x) {
return t.insert_unique(position, x);
}
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
void insert(InputIterator first, InputIterator last) {
t.insert_unique(first, last);
}
#else
void insert(const value_type* first, const value_type* last) {
t.insert_unique(first, last);
}
void insert(const_iterator first, const_iterator last) {
t.insert_unique(first, last);
}
#endif /* __STL_MEMBER_TEMPLATES */
void erase(iterator position) { t.erase(position); }
size_type erase(const key_type& x) { return t.erase(x); }
void erase(iterator first, iterator last) { t.erase(first, last); }
void clear() { t.clear(); }
// map operations:
iterator find(const key_type& x) { return t.find(x); }
const_iterator find(const key_type& x) const { return t.find(x); }
size_type count(const key_type& x) const { return t.count(x); }
iterator lower_bound(const key_type& x) {return t.lower_bound(x); }
const_iterator lower_bound(const key_type& x) const {
return t.lower_bound(x);
}
iterator upper_bound(const key_type& x) {return t.upper_bound(x); }
const_iterator upper_bound(const key_type& x) const {
return t.upper_bound(x);
}
//注意返回的是pair
pair equal_range(const key_type& x) {
return t.equal_range(x);
}
pair equal_range(const key_type& x) const {
return t.equal_range(x);
}
friend bool operator== __STL_NULL_TMPL_ARGS (const map&, const map&);
friend bool operator< __STL_NULL_TMPL_ARGS (const map&, const map&);
};
template <class Key, class T, class Compare, class Alloc>
inline bool operator==(const map & x,
const map & y) {
return x.t == y.t;
}
template <class Key, class T, class Compare, class Alloc>
inline bool operator<(const map & x,
const map & y) {
return x.t < y.t;
}
#ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDER
template <class Key, class T, class Compare, class Alloc>
inline void swap(map & x,
map & y) {
x.swap(y);
}
#endif /* __STL_FUNCTION_TMPL_PARTIAL_ORDER */
#include
#include
using namespace std;
int main()
{
map<int, string> m;
pair<int, string> val(2, "234");
//自己创建pair,调用insert插入
m.insert(make_pair(1, "23"));
m.insert(val);
/* 使用下标操作符插入
* 其内部也是调用insert,m[key]返回的是key对应的value,返回的是引用
*/
m[3] = "sdasd";
m[5] = "qeqwas";
map<int, string>::iterator ite1 = m.begin();
map<int, string>::iterator ite2 = m.end();
//遍历,注意迭代器指向的是pair,要访问key或者value不能直接取值
while(ite1 != ite2)
{
cout << "key: " << ite1->first << " value: " << ite1->second << endl;
ite1++;
}
/* 最好使用map自带的find函数,因为底层是红黑树实现的,查找操作很快
* 而算法中的find函数,后面我们会见识到
* 不太适合这种关联式容器
*/
ite1 = m.find(4);
if(ite1 == m.end())
{
cout << "not found" << endl;
}
else
{
cout << "i found it, the value is:" << ite1->second << endl;
}
return 0;
}
本小节中我们讨论了map
容器的实现,它和set
最大的不同就是它存储的单位是pair
,是key-value
型的,并且支持下标运算。
除了set
、map
,还有它们的一个变种,即允许重复的元素插入,分别是multiset
和multimap
,接下来我们分别展示它们。