STL与泛型编程<六>:map和multimap

Map和Multimap将key/value pair当作元素,进行管理。它们可根据key的排序准则自动将元素进行排序。其声明如下

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(可比较的)

maps和multimaps的能力

内部结构如下图

和set一样,map具有很好的排序功能,当然你不能改变其key,因为破坏了正确次序。要修改元素的key,必须先移除拥有该key的元素,然后插入新的key/value.

maps和multimaps的操作函数

  • 生成 赋值 销毁
  • 非变动性操作
    STL与泛型编程<六>:map和multimap_第1张图片
    元素的比较只能用于相同型别的容器,也就是容器的key/value/排序准则都必须一样。
  • 特殊的搜寻动作
    STL与泛型编程<六>:map和multimap_第2张图片
    你不能以find()搜寻拥有某特定value的元素,必须使用通用算法find_if(),或写一个显示循环。
  • 赋值
    STL与泛型编程<六>:map和multimap_第3张图片
  • 迭代器函数和元素存取
    STL与泛型编程<六>:map和multimap_第4张图片
    由于key的类型是const,所以不能直接改变。若要改变key,只能以一个”value相同”的新元素替代换掉旧元素,见下面的函数
template <typename T>
inline bool replace_key(T& c, const T::key_type& old_key, const T::key_value& new_key)
{
    typename T::iterator pos;
    pos = c.find(old_key);
    if (pos != c.end())
    {
        c.insert(typename T::value_type(new_key,pos->second));
        c.erase(pos);
        return true;    
    }   
    else
        return false;
} 

注意由于maps可以用[]来存取元素,因此还可以这样来替换key

col["new_key"] = col["new_key"];
col.erase("old_keys");
  • 元素的安插和移除
    和sets和multisets一样,只是返回值不一样,是key/value pair。
    安插一个key/value时,一定要记住,在map和multimap内部,key被视为常数,元素的实质类型为pair
map<string,float> col;
col.insert(map<string,float>::value_type("otto",22.3));
  1. 运用pair<>
map<string,float> col;
//use implicit conversion
col.insert(pair<string,float>("otto",22.3));
//use no implicit conversion
col.insert(pair<const string,float>("otto",22.3));
  1. 运用make_pair()
map<string,float> col;
col.insert(make_pair("otto",22.3));

最方便的就是make_pair了,下面是个简单的例子,检查插入是否成功


map<string,float> col;
if ( col.insert(make_pair("shi",12.3)).second )  //插入成功 
{

}
else//插入失败

如果想要移除拥有某个value元素,可以运用erase()可办到,其返回移除元素的个数,对于map来说不是0就是1

col.erase(key);

如果multimap内含有重复元素,你不能使用erase()来删除这些重复元素中的第一个(因为C++根本不知道删除的是哪一个),你可以这么做

multimap<string,int> col;
...
multimap<string,int>::iterator pos;
pos = col.find(key);
if (pos != key)
{
    col.erase(key);
}

以下重要移除元素时,当你移除迭代器所指对象时,有一个很大的危险

map<string,int> col;
...
multimap<string,int>::iterator pos;
for (pos=col.begin(); pos != col.end(); ++pos)
{
    if (pos->second == value)
        col.erase(pos);
}

如果删除了pos,光是一个++pos就会产生未定义行为。
下面是移除“迭代器所指元素的正确做法”

map<string,int> col;
...
multimap<string,int>::iterator pos;
for (pos=col.begin(); pos != col.end();)
{
    if (pos->second == value)
        col.erase(pos++);
    else
        ++pos;
}

至于为什么,只要懂得前置++和后置++的一看就明白了。

  • 将map置为关联式数组
    通常关联是容器并不提供元素的直接存取,你必须依靠迭代器,不过map是个例外
m[key];//返回一个reference,指向键值为key的元素,如果该元素不存在,就安插该元素

注意你不可能用上一个错误的索引,而容器中尚未存在对应元素,那么就会自动安插该元素,新元素的value会由default构造函数构造
1. 优点:很容易就可以安插元素
2. 缺点:很容易安插错误的元素

  • map应用实例
#include <iostream>
#include <map>
#include <iterator>

using namespace std;

int main(void)
{
    map<string,float> stocks;
    stocks["BASF"] = 369.50;
    stocks["VW"] = 413.50;
    stocks["Daimler"] = 819.00;
    stocks["BMW"] = 834.00;
    stocks["Simens"] = 842.20;

    map<string,float>::iterator pos;
    for (pos=stocks.begin(); pos!=stocks.end(); ++pos)
    {
        cout << "stocks: " << pos->first << "\t"
             << "prices: " << pos->second << endl;
    }
    cout << endl;

    for (pos=stocks.begin(); pos!=stocks.end(); ++pos)
    {
        pos->second *= 2;
    }

    for (pos=stocks.begin(); pos!=stocks.end(); ++pos)
    {
        cout << "stocks: " << pos->first << "\t"
             << "prices: " << pos->second << endl;
    }

    stocks["Volk"] = stocks["VW"];
    stocks.erase("VW");

    return 0;
}
  • multimap当作字典
#include <iostream>
#include <map>
#include <iomanip>

using namespace std;

int main(void)
{
    multimap<string,string> dict;

    dict.insert(make_pair("day","Tag"));
    dict.insert(make_pair("strange","Atuo"));
    dict.insert(make_pair("smart","elegant"));
    dict.insert(make_pair("trait","Merkmal"));
    dict.insert(make_pair("strange","seltsam"));
    dict.insert(make_pair("smart","klug"));
    dict.insert(make_pair("clever","raffiniert"));

    multimap<string,string>::iterator pos;
    cout.setf (ios::left, ios::adjustfield);
    cout << ' ' << setw(10) << "english "
         << "german " << endl;
    cout << setfill('-') << setw(20) << " "
         << setfill(' ') << endl;

    for (pos=dict.begin(); pos!=dict.end(); ++pos)
    {
        cout << ' ' << setw(10) << pos->first.c_str()
            << pos->second << endl;
    }
    cout << endl;

    string word("smart");
    cout << word << ": " << endl;
    for (pos=dict.lower_bound(word); pos!=dict.upper_bound(word); ++pos)
    {
        cout << " " << pos->second << endl;
    }

    word = ("raffinert");
    cout << word << ": " << endl;
    for (pos=dict.begin(); pos!=dict.end(); ++pos)
    {
        if (pos->second == word)
            cout << " " << pos->first << endl;
    }
    return 0;
}
  • 搜寻某个特定实值(values)的元素
    解法1:自己写仿函数
#include <iostream>
#include <algorithm>
#include <map>
#include <functional>

using namespace std;

template<typename K, typename V>
class value_equals
{
    private:
        V _val;
    public:
        value_equals(const V& val) : _val(val) {}
        bool operator() (pair<const K,V> elem)
        {
            return elem.second == _val;
        }
};

int main(void)
{
    map<float,float> col;
    map<float,float>::iterator pos;
    col[1] = 7;
    col[2] = 4;
    col[3] = 2;
    col[4] = 3;
    col[5] = 6;
    col[6] = 1;
    col[7] = 3;

    pos = col.find(3);
    if (pos != col.end())
        cout << pos->first << ":" << pos->second << endl;
    pos = find_if(col.begin(),col.end(),value_equals<float,float>(3));
    if (pos != col.end())
        cout << pos->first << ":" << pos->second << endl;
    return 0;
}
/* 上面是写了个仿函数, */

解法2:使用全局函数

#include <iostream>
#include <algorithm>
#include <map>
#include <functional>
using namespace std;

template<typename K, typename V>
bool my_equal(pair<const K,V> elem, V val)
{
    return elem.second == val;
}

int main(void)
{
    map<float,float> col;
    map<float,float>::iterator pos;
    col[1] = 7;
    col[2] = 4;
    col[3] = 2;
    col[4] = 3;
    col[5] = 6;
    col[6] = 1;
    col[7] = 3;

    pos = col.find(3);
    if (pos != col.end())
        cout << pos->first << ":" << pos->second << endl;
    pos = find_if(col.begin(),col.end(),bind2nd(ptr_fun(my_equal<float,float>),3));
    if (pos != col.end())
        cout << pos->first << ":" << pos->second << endl;
    return 0;
}
/* 写个全局函数,然后使用ptr_fun()接口使之能够使用仿函数适配器 */

你可能感兴趣的:(STL与泛型编程<六>:map和multimap)