map/multimap类模板
与前面所学容器都不相同,map与multimap中存储的是元素对(key-value),映射类型的容器通常也可理解为关联数组,可使用键作为下标来获取对应的值,关联的本质在于元素的值与某个特定的键相关联,而不是通过在数组中的位置来获取。接下来我们就来学习一下映射的对象创建及常用操作方法。
1、创建对象
map与multimap中也重载了不同的构造函数,可用不同的方式创建对象,map对象的创建方式有以下几种:
map<T1, T2> m; //创建一个空的map容器
map<T1,T2, op> m; //创建一个空的map容器,以op为准则排序
map<T1, T2> m(begin, end); //创建一个map容器,用[begin, end)区间值赋值
map<T1, T2> m(begin,end,op);//创建一个map容器,用[begin, end)区间值赋值,op为排序准则
map<T1, T2> m(m1); //创建一个map容器,用另一个map容器m1初始化
map对象的创建方式有以上五种,接下来我们分别用这五种方式创建不同的map对象,代码如下所示:
map<int, int> m1;
map<char, float, greater<int>()> m2;
map<string, int> m3(begin, end);
map<string, int, greater<string>()> m4(begin, end);
map<int, int> m5(m1);
上述代码分别调用不同的构造函数创建了五个map对象,注意,在创建map对象时,类型参数必须有两个。
与map一样,multimap也重载了这五种类型的构造函数,接下来我们再用这五种方式创建multimap的对象,代码如下所示:
multimap<int, int> mt1;
multimap<char, float, greater<int>()> mt2;
multimap<string, int> mt3(begin, end);
multimap<string, int, greater<string>()> mt4(begin, end);
multimap<int, int> mt5(m1);
上述代码分别用五种不同的方式创建了不同的multimap对象,其中参数含义与map一样,这里不再赘述。
2、元素的访问与统计及容器大小
对于map容器来说,支持[]运算来通过键访问值,同时map也提供了at()函数来随机访问容器中的元素,例如下面的代码:
m.at(key);
m[key];
map容器可以通过这两种方式来随机访问容器中元素,但multimap中允许存在重复的键值,因此无法使用这两种方式来随机访问容器中元素。
注意:上述m对象,在后面讲解中,如无特殊说明,代表map或multimap。
与集合一样,映射也提供了count()、max_size()与size()分别用于统计元素的个数、求算容器最大存储量和容器大小,其函数调用如下所示:
m.count(key);
m.max_size();
m.size();
因为map中无重复元素,因此其count()计算结果只有0和1,而multimap会有多个值。
3、获取头尾部元素
和其他容器一样,映射也提供了begin()与end()两个函数分别用于获取头部与尾部元素,其函数调用如下所示:
m.begin(); //返回容器中首元素的迭代器
m.end(); //返回容器中最后一个元素之后的迭代器
这两个函数的调用与其他容器方式相同,这里就不再赘述。
4、插入和删除元素
map和multimap的成员函数insert()用于插入元素,其函数调用有三种形式,如下所示:
m.insert(elem); //在容器中插入元素elem
m.insert(pos, elem); //在pos位置插入元素elem
m.insert(begin, end); //在容器中插入[begin, end)区间的值
因为映射中存储的是键值对,因此其插入函数与其他容器稍有不同,要每次插入一对元素,参数中的elem指的是一对元素,接下来我们详细讲解如何用insert()函数将一对元素插入容器中。
(1)使用pair<>构建键值对对象
在插入元素时使用pair<>语句来标识插入的键值对,代码如下所示:
map<int, float> m; //也适用于multimap容器
m.insert(pair<int, float>(10,2.3));
在上述语句中,是用10,2.3构造了一个pair对象,即一个元素对,然后将这个元素对作为insert()函数的参数插入到容器中。
(2)使用make_pair()函数构建键值对对象
我们知道,pair对象的创建可以调用其构造函数,也可以调用make_pair()函数,因此insert()还可以与make_pair()函数结合使用将键值对插入到容器中,如下代码所示:
map<int, float> m; //也适用于multimap容器
m.insert(make_pair(10,2.3));
同样,使用make_pair()函数构造了一个pair对象,然后将这个对象作为参数插入到了容器中。
(3)使用value_type标志
value_type是容器中内部定义的typedef,标识着容器元素类型,因此insert()与value_type结合使用也可以将数据插入到容器中,代码如下所示:
map<int, float> m; //也适用于multimap容器
m.insert(map<int,float>::value_type(10,2.3));
value_type是容器中自定义的数据类型,它可以将传入的10与2.3自动与容器类型匹配,从而将数据插入到容器中。
这三种方式都是用insert()第一种实现方式讲解,对于另外两种insert()实现方式同样适用。
除了insert()函数,map容器还可以用下标方式插入元素,此时可以将map容器视为关联数组,调用形式如下所示:
m[key] = value; //m只能是map容器,不适用于multimap
m[key]返回一个引用,该引用指向键值为key的元素,如果该元素尚未存在,则插入该元素,如果该元素已存在,则新插入的元素会覆盖原有的元素。
m[key]中的索引值“key”不一定是整型,它与容器中的键类型对应,例如:
map<char,string> m;
m1['a'] = "abc";
此时,key为char类型。但需要注意的是,下标法只适用于map容器,因为multimap容器中允许重复元素,因此无法用下标法插入元素。
与插入元素相对应,map与multimap也提供了erase()函数用于删除容器中的元素,该函数调用也有三种形式,如下所示:
m.erase(pos); //删除位置pos上的元素,返回下一个元素的迭代器
m.erase(begin, end); //删除[begin, end)范围内的元素,返回下一个元素的迭代器
m.erase(key); //删除键为key的元素对
学习了map与multimap常用的几个操作函数,接下来我们通过一个案例来演示其用法,具体如例1所示。
例1
1 #include <iostream>
2 #include <map>
3 #include <functional>
4 #include <string>
5 using namespace std;
6 //定义printm()函数输出map容器元素
7 void printm(map<char, double> mymap)
8 {
9 pair<char, double> p; //创建pair对象,map中元素是成对的,也要成对输出
10 map<char, double>::iterator it; //定义迭代器
11 for (it = mymap.begin(); it != mymap.end(); it++)
12 {
13 p = (pair<char, double>)*it; //将迭代器指向的一对元素存放到p中
14 cout << p.first << "->" << p.second << endl; //输出一对元素
15 }
16 }
17
18 //定义printmt()函数输出multimap容器
19 void printmt(multimap<int, string> mymul)
20 {
21 pair<int, string> p;
22 multimap<int, string>::iterator it;
23 for (it = mymul.begin(); it != mymul.end(); it++)
24 {
25 p = (pair<int, string>)*it;
26 cout << p.first << "->" << p.second << endl;
27 }
28 }
29
30 int main()
31 {
32 map<char, double> m; //创建一个map容器
33 //向容器m中插入元素
34 m['a'] = 1.2;
35 m['b'] = 3.6;
36 m['c'] = 6.4;
37 m['d'] = 0.8;
38 m['e'] = 5.3;
39 m['f'] = 3.6;
40
41 cout << "map: " << endl;
42 printm(m);
43 cout << "map中key = a的值: " << m.at('a') << endl;
44 cout << "map中key = f的元素出现次数: " << m.count('f') << endl;
45
46 multimap<int, string> mt; //创建一个multimap容器
47 //向容器mt中插入元素
48 mt.insert(pair<int, string>(1, "chuan"));
49 mt.insert(make_pair(1, "zhi"));
50 mt.insert(multimap<int, string>::value_type(3, "bo"));
51 mt.insert(multimap<int, string>::value_type(4, "ke"));
52
53 cout <<endl<< "multimap: " << endl;
54 printmt(mt);
55 cout << "multimap头部元素: ";
56 pair<int, string> p;
57 p = (pair<int, string>)*mt.begin();
58 cout << p.first << "->" << p.second << endl;
59 cout << "multimap尾部元素: ";
60 p = (pair<int, string>)*(--mt.end());
61 cout << p.first << "->" << p.second << endl;
62 system("pause");
63 return 0;
64 }
运行结果如图1所示。
图1 例运行结果
在例1中定义了一个map容器m和一个multimap容器mt,接下来我们将本案例分为三个部分来讲解。
● 在例1开头定义了两个函数printm()与printmt(),分别用于输出map与multimap容器中的元素,两个函数实现相同,我们以print()讲解为主,因为映射中的元素都是成对的,因此第9行代码先创建了一个pair<>对象p,第10行代码定义了一个map<char,double>类型的迭代器it,接下来用一个for循环来获取容器中元素,在for循环中,第13行代码将迭代器指向的元素对存储到p中,然后第14行代码分别用pair<>的成员first与second将一对元素输出。
● 代码32行创建了一个map<char, float>容器m,代码34-39行用[]运算符向容器中插入元素,代码42行调用printm()函数输出m容器中的元素,由图8-15可知,容器中元素正确输出。代码43行调用at()函数随机访问键值为'a'的元素值,代码第44行调用count()函数统计键值为f的元素出现的次数,由图8-15可知,其出现次数为1。
● 代码第46行创建了一个multimap<int, strig>容器mt,代码48-51行向容器中插入元素,分别运用了pair<>、make_pair()与value_type三种形式向容器中插入元素。代码54行调用printmt()输出mt容器中的元素,由图8-15可知,容器中元素成功输出。代码55-58行输出容器中的头部元素,因为元素包括两个值,因此代码56行先创建了一个pair<>对象,接着57行代码调用begin()函数将头部的元素对存储到p中,58行代码调用pair中的first与second将值输出。代码59-61行输出尾部元素也是如此,只是end()函数返回的是末尾元素的下一个位置,因此end()获取的迭代器要先前移一个位置到末尾元素,再进行运算。