map翻译为映射,也是常用的STL容器。在定义数组时,其实是定义了一个int型到其他型的映射。如int arry[100],其实就是定义了一个从int型到int型的映射,比如arry[0]=20,arry[1]=30就分别是将0映射到20,1映射到30。它有一个弊端,当需要以其他类型作为关键字是时,就不太容易操作。比如有一本字典,上面由很多单词与单词对应的页码,若用数组表示“单词-->页码”的对应关系,就很难做到。这时就可以用到map,因为map可以将任何基本类型(包括STL容器)映射到任何基本类型(包括STL容器),也就可以建立string型到int型的映射。
还可以来看这样一个情况,这次需要判断给定的一些数字在某个文件是否出现过。按照以前所学,可以开一个bool型的hashTable[max_size],通过判断hashTable[x]为true还是false来确定x是否在文件中出现过。但会碰到一个问题,如果这些数字很大(例如有几千位),那么这个数组可能就会开不了了。而这时map就可以派上用场了,因为map可以将这些数字当成一些字符串,然后建立string到int的映射(或者直接建立int到int的映射?)。
如果要使用map,需要添加map的头文件 #include<map>,并且在头文件下加 using namespace std; 。
1、map的定义
单独定义一个map:
map<typename1, typename2> mp;
map和其他STL容器在定义上有点不一样,因为map需要确定映射前类型(键key)和映射后类型(值value),所以需要在<>内填写两个类型,其中第一个时键的类型,第二个时值的类型。如果时int到int型,就相当于普通的int数组。
而如果是字符串到整型的映射,必须使用string而不能用char数组,这是因为char数组作为数组,是不能被作为键值的。
map<string,int> mp;
前面也说到,map的键和值也可以是STL容器,例如可以将一个set容器映射到一个字符串:
map<set<int>,string>;
2、map容器内元素的访问
map一般有两种访问方式,通过迭代器或者通过下标访问。
(1)通过下标访问
和访问普通的数组时一样的,例如对于一个定义为map<char,int> mp的map来说,就可以直接使用map['c']的方式来访问它对应的整数。于是,当建立映射时,就可以直接使用mp['c']=20,这样和数组一样的方式。但要注意,map中的键时唯一的。
#include<cstdio>
#include<map>
using namespace std;
int main(){
map<char,int> mp;
mp['c']=20;
mp['c']=30; //map中键时唯一的,20会被覆盖
printf("%d",mp['c']); //输出30
return 0;
}
(2)通过迭代器访问
map迭代器的定义和其他STL容器迭代器的方式相同:
map<typename1, typename2> :: iterator it;
typename1,typename2就是定义map时填写的类型,这样就得到了迭代器it。
map迭代器的使用和其他STL容器的迭代器不同,因为map的每一对映射都有两个typename,这决定了必须通过一个it来同时访问键和值,map可以使用 it->first来访问键,使用it->second来访问值。
示例:
#include<cstdio>
#include<map>
using namespace std;
int main(){
map<char,int> mp;
mp['m']=20;
mp['a']=30;
mp['r']=40;
for(map<char,int>::iterator it =mp.begin(); it!=mp.end(); it++){
printf("%c %d\n",it->first,it->second);
}
return 0;
}
输出:
由输出结果发现,map会以键从小到大的顺序自动排序,即按 a<m<r 的顺序排列这三对映射。这是由于map内部的红黑树实现的(set也是),在建立映射的过程中会自动实现从小到大的排序功能。
3、map常用函数示例
(1)find( )
find(key)返回键为key的映射的迭代器,时间复杂度为O(logN),N为map中映射的个数。
示例:
#include<cstdio>
#include<map>
using namespace std;
int main(){
map<char, int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
map<char,int>::iterator it=mp.find('b');
printf("%c %d\n",it->first,it->second);
return 0;
}
输出结果:
(2)erase( )
erase( )有两种用法:删除单个元素、删除一个区间内所有元素。
①删除单个元素
删除单个元素有两种方法:
- mp.erase(it),it为需要删除的元素的迭代器。时间复杂度为O(1)。
示例:
#include<cstdio>
#include<map>
using namespace std;
int main(){
map<char, int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
map<char,int>::iterator it=mp.find('b');
mp.erase(it); //删除 b,2
for(map<char,int>::iterator it=mp.begin(); it !=mp.end(); it++)
printf("%c %d\n",it->first,it->second);
return 0;
}
输出:
- mp.erase(key),key为欲删除的映射的键。时间复杂度为O(logN),N为map内元素的个数。
示例:
#include<cstdio>
#include<map>
using namespace std;
int main(){
map<char, int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
//map<char,int>::iterator it=mp.find('b');
mp.erase('b'); //删除 键为b的映射, 即 b 2
for(map<char,int>::iterator it=mp.begin(); it !=mp.end(); it++)
printf("%c %d\n",it->first,it->second);
return 0;
}
输出:
②删除一个区间内的所有元素
mp.erase(first,last); 其中first为需要删除的区间的起始迭代器,而last则为需要删除的区间的末尾迭代器的下一个地址,也即为删除左闭右开的区间 [first,last) 。时间复杂度为O(last-first)。
示例:
#include<cstdio>
#include<map>
using namespace std;
int main(){
map<char, int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
map<char,int>::iterator it=mp.find('b'); //令it指向键为b的映射
mp.erase(it,mp.end()); //删除it后的所有映射,即 b 2和 c 3
for(map<char,int>::iterator it=mp.begin(); it !=mp.end(); it++)
printf("%c %d\n",it->first,it->second);
return 0;
}
输出:
(3)size( )
size( )用来获取map中映射的对数,时间复杂度为O(1)。
示例:
#include<cstdio>
#include<map>
using namespace std;
int main(){
map<char, int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
printf("%d\n",mp.size());
return 0;
}
输出:
(4)clear( )
clear( )用来清空map中的所有元素,复杂度为O(N),其中N为map中元素的个数。
示例:
#include<cstdio>
#include<map>
using namespace std;
int main(){
map<char, int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
mp.clear(); //清空map
printf("%d\n",mp.size());
return 0;
}
输出:
4、map的常见用途
①需要建立字符(或字符串)与整数之间的映射的题目,使用map可以减少代码量。
②判断大整数或者其他类型数据是否存在的题目,可以把map当作bool数组来用。
③字符串和字符串的映射有时也可能会遇到。