Map和Multimap将键值对key/value pair作为元素,进行管理。它们可以根据key的排序准则自动给元素排序。
Multimap允许重复元素,而Map不允许。
定义:
namespace std{
template<class Key,class T,class Compare = less<Key>,class Allocator = allocator<pair<const Key,T>>>
class map;
template<class Key,class T,class Compare = less<Key>,class Allocator = allocator<pair<const Key,T>>>
class multimap;
}
元素要求:
1)key/value必须是assignable和copyable的
2)key必须是comparable,和set一样,这个排序规则被定义为strict week ordering。
Map能力:
和一般关联式容器一样,Map是由平衡二叉树来实现的。
典型情况下,set和map是具有相同的内部数据结构,可将Map视作特殊的Set。
Map拥有set所有的能力和操作函数,存在很少差异:
1)元素是键值对
2)Map可以作为关联式数组来运用
元素的value可以修改,前提是它是非const的。
2.操作函数
用MAP表示以下形式:
map<Key,Elem>; map<Key,Elem,Op>;
multimap<Key,Elem>; multimap<Key,Elem,Op>;
# Constructor and Destructor
MAP m; MAP m(op); MAP m(m2);
MAP m(beg,end); MAP m(beg,end,op); //确保源容器中元素等于或可以转化为新容器的元素
m.~MAP();
由上可以看出有两种方式定义排序规则:
1) 以模板参数定义
std::map<float,std::string,std::greater<float>> m;
使用Typedef简化类型定义
typedef std::map<float,std::string,std::greater<float>> StringFloatMap;
StringFloatMap m;
2)以构造函数定义,调用MAP m(op):
MAP m(std::greater<float>);
# Nonmodifying Operations
m.size(); m.empty(); m.maxsize();
Comparision Operators like != <= < //不同型别的容器不能做比较
# Special Search Operations
和set一样,map提供特殊的搜索函数,以便利用内部树状结构以获得较好的性能。
m.count(key); m.find(key);
m.lower_bound(key); m.upper_bound(key);
m.equal_range(key);
如果想对特殊的value元素,做特定操作,需要自定义:
StringFloatMap m;
StringFloatMap::interator pos;
for(pos = m.begin(); pos != m.end(); ++pos){
if(pos->second == value) do something;
}
# Assignments
m1 = m2; m1.swap(m2); swap(m1,m2);
# Iterator Functions and Elements Access
Map不支持直接存取,所有的存取必须通过iterator。
类似于所有的关联式容器,返回的是一个双向迭代器,而不是一个随机存取迭代器。
例外的是,map提供下标操作符进行元素存取,使用key做下标。
m.begin(); m.end();
m.rbegin(); m.rend();
在map中,所有的key都被视为const,因此元素的型别实际是pair<const Key,T>。
变更元素的key,会修改了原本的元素次序,所以不能针对map调用任何变更型算法modifying algorithms,remove函数肯定是不能用了。
如果一定要修改元素的key,只能通过删除原来的元素,同时使用一个value相同的新元素来替代它了。
一个修改key的泛化函数:
template <class Cont>
inline bool replace_key(Cont& c,
const typename Cont::key_type& old_key
const typename Cont::key_type& new_key){
typename Cont::iterator pos;
pos = c.find(old_key);
if(pos != c.end()){
c.insert(typename Cont::value_type(new_key,pos->second));
c.erase(old_key);
return true;
}
else{
return false;
}
}
其实使用下标可以更方便地修改:
m["new_key"] = m["old_key"]; //对于m["new_key"]的操作,如果new_key不存在,那么插入一个这样的元素,value使用默认构造函数初始化
m.erase("old_key");
# Inserting and Removing
类似于set,特别是返回值差异与set一样,那么就是说map中插入可能失败,将会有返回值为一个pair的特殊函数。
m.insert(elem); m.insert(pos,elem); m.insert(beg,end);
m.erase(elem); m.erase(pos); m.erase(beg,end);
安插key/value pair的方法,要么正确型别,要么就是隐形或显性的类型转换:
1)运用value_type
StringFloatMap m;
m.insert(StringFloatMap::value_type("tolto",2.2));
2)运用pair<>
m.insert(pair<string,float>("tolto",2.2));
3)使用make_pair()
m.insert(make_pair("tolto",2.2))
和set类似的考虑:
要移除单个元素,使用erase()就可以办到,但是对于多个元素的Multimap,不能使用erase()只删除第一个,而应该转为找到第一位置,通过标识位置pos的迭代器来删除单一位置的元素。
通过迭代器删除erase(pos),会是迭代器pos失效,以下是存在危险的:
for(pos = m.begin(); pos != m.end(); ++pos){
if(pos->second == value) m.erase(pos); //pos已经失效
}
正确的做法:
for(pos = m.begin(); pos != m.end(); ){
if(pos->second == value) { m.erase(pos++);} //pos++会将pos后移,同时返回原位置的副本
else ++pos;
}
3.将map视为关联式数组Associative Arrays
通常,关联式容器不支持直接存取的,map是个特例。
Non-const map支持下标操作符,支持元素的直接存取,下标的索引值是key,m[Key],这就是所谓的关联式数组。
4.map运用实例
#include<iostream>
#include<string>
#include<map>
using namespace std;
//模拟股票
int main(){
typedef map<String,float> StringFloatMap;
StringFloatMap Stocks;
Stocks["alibaba"] = 345.3;
Stocks["360"] = 327.7;
Stocks["baidu"] = 426.8;
Stocks["xiaomi"] = 345.0;
Stocks["tecent"] = 485.3;
StringFloatMap::iterator pos;
for(pos = m.begin();m != m.end();++pos;){
cout<<"stock:"<<pos->first<<"\t"
<<"price:"<<pos->second<<endl;
}
cout<<endl;
for(pos = m.begin(); m != m.end();++pos){
pos->second *= 2;
}
for(pos = m.begin();m != m.end();++pos;){
cout<<"stock:"<<pos->first<<"\t"
<<"price:"<<pos->second<<endl;
}
cout<<endl;
Stocks["souhu"] = Stocks["baidu"];
Stocks.erase("360");
for(pos = m.begin();m != m.end();++pos;){
cout<<"stock:"<<pos->first<<"\t"
<<"price:"<<pos->second<<endl;
}
cout<<endl;
}
Multimap允许重复元素,而Map不允许。
定义:
namespace std{
template<class Key,class T,class Compare = less<Key>,class Allocator = allocator<pair<const Key,T>>>
class map;
template<class Key,class T,class Compare = less<Key>,class Allocator = allocator<pair<const Key,T>>>
class multimap;
}
元素要求:
1)key/value必须是assignable和copyable的
2)key必须是comparable,和set一样,这个排序规则被定义为strict week ordering。
Map能力:
和一般关联式容器一样,Map是由平衡二叉树来实现的。
典型情况下,set和map是具有相同的内部数据结构,可将Map视作特殊的Set。
Map拥有set所有的能力和操作函数,存在很少差异:
1)元素是键值对
2)Map可以作为关联式数组来运用
元素的value可以修改,前提是它是非const的。
2.操作函数
用MAP表示以下形式:
map<Key,Elem>; map<Key,Elem,Op>;
multimap<Key,Elem>; multimap<Key,Elem,Op>;
# Constructor and Destructor
MAP m; MAP m(op); MAP m(m2);
MAP m(beg,end); MAP m(beg,end,op); //确保源容器中元素等于或可以转化为新容器的元素
m.~MAP();
由上可以看出有两种方式定义排序规则:
1) 以模板参数定义
std::map<float,std::string,std::greater<float>> m;
使用Typedef简化类型定义
typedef std::map<float,std::string,std::greater<float>> StringFloatMap;
StringFloatMap m;
2)以构造函数定义,调用MAP m(op):
MAP m(std::greater<float>);
# Nonmodifying Operations
m.size(); m.empty(); m.maxsize();
Comparision Operators like != <= < //不同型别的容器不能做比较
# Special Search Operations
和set一样,map提供特殊的搜索函数,以便利用内部树状结构以获得较好的性能。
m.count(key); m.find(key);
m.lower_bound(key); m.upper_bound(key);
m.equal_range(key);
如果想对特殊的value元素,做特定操作,需要自定义:
StringFloatMap m;
StringFloatMap::interator pos;
for(pos = m.begin(); pos != m.end(); ++pos){
if(pos->second == value) do something;
}
# Assignments
m1 = m2; m1.swap(m2); swap(m1,m2);
# Iterator Functions and Elements Access
Map不支持直接存取,所有的存取必须通过iterator。
类似于所有的关联式容器,返回的是一个双向迭代器,而不是一个随机存取迭代器。
例外的是,map提供下标操作符进行元素存取,使用key做下标。
m.begin(); m.end();
m.rbegin(); m.rend();
在map中,所有的key都被视为const,因此元素的型别实际是pair<const Key,T>。
变更元素的key,会修改了原本的元素次序,所以不能针对map调用任何变更型算法modifying algorithms,remove函数肯定是不能用了。
如果一定要修改元素的key,只能通过删除原来的元素,同时使用一个value相同的新元素来替代它了。
一个修改key的泛化函数:
template <class Cont>
inline bool replace_key(Cont& c,
const typename Cont::key_type& old_key
const typename Cont::key_type& new_key){
typename Cont::iterator pos;
pos = c.find(old_key);
if(pos != c.end()){
c.insert(typename Cont::value_type(new_key,pos->second));
c.erase(old_key);
return true;
}
else{
return false;
}
}
其实使用下标可以更方便地修改:
m["new_key"] = m["old_key"]; //对于m["new_key"]的操作,如果new_key不存在,那么插入一个这样的元素,value使用默认构造函数初始化
m.erase("old_key");
# Inserting and Removing
类似于set,特别是返回值差异与set一样,那么就是说map中插入可能失败,将会有返回值为一个pair的特殊函数。
m.insert(elem); m.insert(pos,elem); m.insert(beg,end);
m.erase(elem); m.erase(pos); m.erase(beg,end);
安插key/value pair的方法,要么正确型别,要么就是隐形或显性的类型转换:
1)运用value_type
StringFloatMap m;
m.insert(StringFloatMap::value_type("tolto",2.2));
2)运用pair<>
m.insert(pair<string,float>("tolto",2.2));
3)使用make_pair()
m.insert(make_pair("tolto",2.2))
和set类似的考虑:
要移除单个元素,使用erase()就可以办到,但是对于多个元素的Multimap,不能使用erase()只删除第一个,而应该转为找到第一位置,通过标识位置pos的迭代器来删除单一位置的元素。
通过迭代器删除erase(pos),会是迭代器pos失效,以下是存在危险的:
for(pos = m.begin(); pos != m.end(); ++pos){
if(pos->second == value) m.erase(pos); //pos已经失效
}
正确的做法:
for(pos = m.begin(); pos != m.end(); ){
if(pos->second == value) { m.erase(pos++);} //pos++会将pos后移,同时返回原位置的副本
else ++pos;
}
3.将map视为关联式数组Associative Arrays
通常,关联式容器不支持直接存取的,map是个特例。
Non-const map支持下标操作符,支持元素的直接存取,下标的索引值是key,m[Key],这就是所谓的关联式数组。
4.map运用实例
#include<iostream>
#include<string>
#include<map>
using namespace std;
//模拟股票
int main(){
typedef map<String,float> StringFloatMap;
StringFloatMap Stocks;
Stocks["alibaba"] = 345.3;
Stocks["360"] = 327.7;
Stocks["baidu"] = 426.8;
Stocks["xiaomi"] = 345.0;
Stocks["tecent"] = 485.3;
StringFloatMap::iterator pos;
for(pos = m.begin();m != m.end();++pos;){
cout<<"stock:"<<pos->first<<"\t"
<<"price:"<<pos->second<<endl;
}
cout<<endl;
for(pos = m.begin(); m != m.end();++pos){
pos->second *= 2;
}
for(pos = m.begin();m != m.end();++pos;){
cout<<"stock:"<<pos->first<<"\t"
<<"price:"<<pos->second<<endl;
}
cout<<endl;
Stocks["souhu"] = Stocks["baidu"];
Stocks.erase("360");
for(pos = m.begin();m != m.end();++pos;){
cout<<"stock:"<<pos->first<<"\t"
<<"price:"<<pos->second<<endl;
}
cout<<endl;
}