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),如果对应元素不存在,那么插入一个新元素,其值按照值类型的缺省构造函数来初始化。
#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