c++标准库——map和multimap容器

来源:互联网 发布:未知usb设备 端口重置 编辑:程序博客网 时间:2024/05/12 06:28
c++标准库——map和multimap容器
四月 12th, 2010 by ewangplay
  • 3791 Views
  • Add Comment
  • Trackback

map和multimap容器跟set和multiset容器非常相似,包括外部接口和内部结构上。不同之处就是set和multiset容器是以单个对象为管理元素,而map和multimap容器是以pair<key, value>为管理元素。map和multimap容器中元素同时是自动排序,它们排序的依据是各个元素的key值。

6.1 map和multimap容器的能力
map和multimap容器在内部结构上通常也采用平衡二叉树(balanced binary tree),拥有跟set和multiset一样的能力和操作。不同之处就是元素形式上,另外map和multimap容器可以作为关联数组使用(这个会在后面说明)。

6.2 map和multimap容器的操作
map和multimap容器的操作接口跟set和multiset容器一样,我们在此就不一一介绍了。只说一下其中需要注意的地方。

插入新元素时,如何正确设置key/value的对应类型?三种不同的途径:
(1)使用value_type()
value_type()是由各个容器自己提供的类型转换接口,使得新添加元素完全符合容器的元素类型。使用例子如下:
std::map<std::string, float> col1;
...
col1.insert(std::map<std::string, float>::value_type("Tom", 85.6));

(2)使用pair<>
因为map和multimap容器的元素是pair实例,因此可以直接使用pair<>来创建新插入的元素。使用例子如下:
std::map<std::string, float> col1;
...
col1.insert(std::pair<std::string, float>("Tom", 85.6));

(3)使用make_pair()
之前我们学习pair类时,已经知道使用make_pair()可以方便地创建一个pair实例,在此也不例外,只是会进行隐式类型转换。使用例子如下:
std::map<std::string, float> col1;
...
col1.insert(std::make_pair("Tom", 85.6));

下面是一个简单的检查插入元素是否成功的代码片段:
std::map<std::string, float> col1;
...
if (col1.insert(std::make_pair("Tom", 85.6)).second) 
{
    std::cout << "insert successfully!" << endl;
}
else
{
    std::cout << "element has been existed!" << endl;
}

6.3 map容器作为关联数组
关联容器通常不提供直接访问元素的能力,但map容器例外,它提供了[]操作符用来直接访问元素。但[]操作符的下表并不是元素在容器中的位置,而是元素的对应key值。这是所谓的关联数组的能力。
  • m[key_val]: 返回容器中键值(key)等于key_val的元素的值(value)引用(reference),如果对应元素不存在,那么插入一个新元素,其值按照值类型的缺省构造函数来初始化。
下面是一个使用map作为关联数组的例子:
#include <iostream>
#include <map>
using namespace std;

int main() 
{
    typedef map<string, float> StringFloatMap;

    //create a empty StringFloatMap set
    StringFloatMap col1;

    //insert some elements
    col1["Tom"] = 67.5;
    col1["John"] = 80.5;
    col1["Mary"] = 90;
    col1["Jekey"] = 78.4;

    //print all the elements of col1
    StringFloatMap::iterator pos;
    for (pos = col1.begin(); pos != col1.end(); ++pos) 
    {
        cout << "key: " << pos->first << "\t" << "value: " << pos->second << endl;
    }
    cout << endl;

    //delete the element with key is Mary
    col1.erase("Mary");

    //insert tow new elements
    col1["Wang"] = 95.4;
    col1["Man"] = 88.5;

    //print all the elements of col1
    for (pos = col1.begin(); pos != col1.end(); ++pos) 
    {
        cout << "key: " << pos->first << "\t" << "value: " << pos->second << endl;
    }
    cout << endl;

    //find the element with key is Man
    pos = col1.find("Man");
    cout << pos->first << "\t" << pos->second << endl;
    cout << endl;
    
    //delete the element with value is 88.5
    for (pos = col1.begin(); pos != col1.end(); ) 
    {
        if (pos->second == 88.5) 
        {
            col1.erase(pos++);
        }
        else
        {
            ++pos;
        }
    }   

    //print all the elements of col1
    for (pos = col1.begin(); pos != col1.end(); ++pos) 
    {
        cout << "key: " << pos->first << "\t" << "value: " << pos->second << endl;
    }
    cout << endl;

    //Modify the key of element with key is Tom
    col1["Zhang"] = col1["Tom"];
    col1.erase("Tom");

    //print all the elements of col1
    for (pos = col1.begin(); pos != col1.end(); ++pos) 
    {
        cout << "key: " << pos->first << "\t" << "value: " << pos->second << endl;
    }
    cout << endl;

    return 0;
}
执行结果如下:
key: Jekey value: 78.4
key: John value: 80.5
key: Mary value: 90
key: Tom value: 67.5

key: Jekey value: 78.4
key: John value: 80.5
key: Man value: 88.5
key: Tom value: 67.5
key: Wang value: 95.4

Man 88.5

key: Jekey value: 78.4
key: John value: 80.5
key: Tom value: 67.5
key: Wang value: 95.4

key: Jekey value: 78.4
key: John value: 80.5
key: Wang value: 95.4
key: Zhang value: 67.5

6.4 查找特定值的元素
在map或者multimap容器中查找特定值的元素,除了传统的遍历元素查找外,还可以使用通用算法来查找,但要自己设计函数对象。下面是一个使用通用算法进行查找特定值元素的例子:
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;

template <typename K, typename V>
class equal_value 
{
    private:
        V value;

    public:
        equal_value(const V& v): value(v) {}
        bool operator() (pair<const K, V> elem)
        {
            return elem.second == value;
        }
};

int main() 
{
    typedef map<float, float> FloatFloatMap;

    //create a empty FloatFloatMap set
    FloatFloatMap col1;

    //insert some elements
    col1[2] = 3;
    col1[4] = 5;
    col1[3] = 6;
    col1[5] = 3;
    col1[1] = 4;
    col1[6] = 1;

    //print all the elements of col1
    FloatFloatMap::iterator pos;
    for (pos = col1.begin(); pos != col1.end(); ++pos) 
    {
        cout << "key: " << pos->first << "\t" << "value: " << pos->second << endl;
    }
    cout << endl;

    //find the element with key 3
    pos = col1.find(3);
    if (pos != col1.end())
    {
        cout << pos->first << "\t" << pos->second << endl;
    }

    //find the elements with value 3
    pos = find_if(col1.begin(), col1.end(), equal_value<float, float>(3));
    if (pos != col1.end())
    {
        cout << pos->first << "\t" << pos->second << endl;
    }

    return 0;
}
执行结果如下:
key: 1 value: 4
key: 2 value: 3
key: 3 value: 6
key: 4 value: 5
key: 5 value: 3
key: 6 value: 1

3 6
2 3

6.5 运行时指定排序法则
对于map容器,我们仍然可能碰到需要两个容器同类型但排序法则不同的情况,下面我们看一个字符串排序的例子:
#include <iostream>
#include <iomanip>
#include <map>
#include <algorithm>
using namespace std;

template <typename T>
class RuntimeStringCmp
{
    public:
        enum Cmp_Mode {normal, nocase};
        
    private:
        Cmp_Mode mode;
        static bool nocase_compare(char c1, char c2)
        {
            return toupper(c1) < toupper(c2);
        }

    public:
        RuntimeStringCmp(Cmp_Mode m=normal) : mode(m) {}
        bool operator() (const T& v1, const T& v2)
        {
            if (mode == normal)
            {
                return v1 < v2;
            }
            else
            {
                return lexicographical_compare(v1.begin(), v1.end(), 
                        v2.begin(), v2.end(), 
                        nocase_compare);
            }
        }
};

//type define
typedef map<string, float, RuntimeStringCmp<string> >  StringFloatMap;

//pre-declare fuction
void FillAndPrint(StringFloatMap m);

int main()
{
    StringFloatMap col1;
    FillAndPrint(col1);

    RuntimeStringCmp<string> nocase_cmp(RuntimeStringCmp<string>::nocase);
    StringFloatMap col2(nocase_cmp);
    FillAndPrint(col2);
}

void FillAndPrint(StringFloatMap m) 
{
    //insert some elements
    m["Deutschland"] = 60;
    m["deutsch"] = 72.5;
    m["Haken"] = 80;
    m["arbeiten"] = 65;
    m["Hund"] = 77;
    m["gehen"] = 88;
    m["Unternehmen"] = 55;
    m["gehen"] = 81;
    m["Bestatter"] = 65.6;

    //print all elements
    StringFloatMap::iterator pos;
    cout.setf(ios::left, ios::adjustfield);
    for (pos = m.begin(); pos != m.end(); ++pos) 
    {
        cout << setw(15) << pos->first.c_str() << " " << pos->second <<endl;
    }
    cout << endl;
}
在这里例子中,col1和col2同样是同类型(key类型相同,value类型相同,sorting criterion类型相同)的map容器,但他们的元素的排序方式却不同:col1的元素按照大小写相关升序排序,而col2按照大小写无关升序排序。它们的排序法则的控制机制仍人跟前面set容器的实例相同。
执行结果如下:
Bestatter       65.6
Deutschland     60
Haken           80
Hund            77
Unternehmen     55
arbeiten        65
deutsch         72.5
gehen           81

arbeiten        65
Bestatter       65.6
deutsch         72.5
Deutschland     60
gehen           81
Haken           80
Hund            77
Unternehmen     55
原创粉丝点击