STL容器之Map

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值