一、前言
在使用 map 容器存储多个键值对时,该容器会自动根据各键值对的键的大小,按照既定的规则进行排序。默认情况下,会根据键的大小对所有键值对做升序排序。
注意点:使用 map 容器存储的各个键值对,键的值既不能重复也不能被修改,即键的类型会用 const 修饰,且是一对一的关系。
使用map容器应包含头文件:
#include <map>
using namespace std; //不是必需的
1、map容器的模板定义
template < class Key, // 指定键(key)的类型
class T, // 指定值(value)的类型
class Compare = less<Key>, // 指定排序规则
class Alloc = allocator<pair<const Key,T> > // 指定分配器对象的类型
> class map;
虽然map的模板有4个参数,但是大多数情况下只需要设置前2个参数即可。
二、创建map容器方法
①std::map<std::string, std::string> myMap;
②std::map<std::string, std::string> myMap{ {"1","lin"},{"2","wei"} };
③std::map<std::string, std::string> newMap(myMap);
④std::map<std::string, std::string> newMap(myMap.begin(), myMap.end());
⑤std::map<std::string, std::string, std::less<std::string> > myMap{ {"1","lin"},{"2","wei"} };
三、map容器方法
此处不列举迭代器、插入和删除相关方法
方法 | 功能 |
---|---|
find(key) | 在 map 容器中查找键为 key 的键值对,如果成功找到,则返回指向该键值对的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器 |
lower_bound(key) | 返回一个指向当前 map 容器中第一个大于或等于 key 的键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器 |
upper_bound(key) | 返回一个指向当前 map 容器中第一个大于 key 的键值对的迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器 |
equal_range(key) | 该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的键为 key 的键值对(map 容器键值对唯一,因此该范围最多包含一个键值对) |
empty() | 若容器为空,则返回 true;否则 false |
size() | 返回当前 map 容器中存有键值对的个数 |
max_size() | 返回 map 容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同 |
operator[] | map容器重载了 [] 运算符,只要知道 map 容器中某个键值对的键的值,就可以向获取数组中元素那样,通过键直接获取对应的值 |
at(key) | 找到 map 容器中 key 键对应的值,如果找不到,该函数会引发 out_of_range 异常 |
count(key) | 在当前 map 容器中,查找键为 key 的键值对的个数并返回。注意,由于 map 容器中各键值对的键的值是唯一的,因此该函数的返回值最大为 1 |
1、实例
1)、lower_bound、upper_bound和equal_range
std::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };
std::map<int, string>::iterator mapIter = mapInfo.lower_bound(1);
std::cout << "lower_bound key: " << mapIter->first << " value: " << mapIter->second << std::endl;
mapIter = mapInfo.upper_bound(1);
std::cout << "upper_bound key: " << mapIter->first << " value: " << mapIter->second << std::endl;
pair<map<int, string>::iterator, map<int, string>::iterator> iters = mapInfo.equal_range(3);
std::map<int, string>::iterator beginIter, endIter;
beginIter = iters.first;
endIter = iters.second;
for (beginIter; beginIter != endIter; beginIter++)
{
std::cout << "equal_range key: " << beginIter->first << " value: " << beginIter->second << std::endl;
}
结果如下:
三、迭代器
stl标准库为map容器配备的是双向迭代器(bidirectional iterator),因此map 容器迭代器只能进行 ++p、p++、--p、p--、*p 操作,并且迭代器之间只能使用 == 或者 != 运算符进行比较。
方法 | 功能 |
---|---|
begin() | 返回指向容器中第一个(注意,是已排好序的第一个)键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器 |
end() | 返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器 |
rbegin() | 返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器 |
rend() | 返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器 |
cbegin() | 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。 |
这个的具体功能不再说明,和序列化容器是一样的功能,唯一不同的就是这里的数据是“键值对”。
对于迭代器的使用,已经有很多的实例,这里就不再说明了。
四、map获取键对应的值
1、通过[]获取
类似于访问数组元素的方式。
std::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };
string strData = mapInfo[1];
std::cout << "strData: " << strData << std::endl;
结果如下:
注意:
1)只有当 map 容器中确实存有包含该指定键的键值对,借助重载的 [ ] 运算符才能成功获取该键对应的值
2)若当前 map 容器中没有包含该指定键的键值对,则此时使用 [ ] 运算符将不再是访问容器中的元素,而变成了向该 map 容器中增添一个键值对
std::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };
mapInfo[5] = "li";
std::map<int, string>::iterator mapIter = mapInfo.begin();
for (; mapIter != mapInfo.end(); mapIter++)
{
std::cout << "key: " << mapIter->first << " value: " << mapIter->second << std::endl;
}
结果如下:
3)其中,该键值对的键用 [ ] 运算符中指定的键,其对应的值取决于 map 容器规定键值对中值的数据类型,如果是基本数据类型,则值为 0;如果是 string 类型,其值为 "",即空字符串(即使用该类型的默认值作为键值对的值)
4)[]具有添加新的键值对的前提是:当前map容器中不存在新添加的键
5)如map容器中已存在对应键,执行map[key] = value是修改键key的值,而不是为 map 容器添加新键值对
mapInfo[5] = "wne";
mapIter = mapInfo.begin();
for (; mapIter != mapInfo.end(); mapIter++)
{
std::cout << "mod key: " << mapIter->first << " value: " << mapIter->second << std::endl;
}
结果如下:
2、at()
需要指定key,才能从容器中找到该键对应的值;如果在当前容器中查找失败,该方法不会向容器中添加新的键值对,而是直接抛出 out_of_range 异常。
std::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };
mapInfo[5] = "li";
try
{
std::cout << mapInfo.at(3) << std::endl;
std::cout << mapInfo.at(10) << std::endl;
}
catch (const std::exception&)
{
std::cout << "调用at获取键对应的值异常" << std::endl;
}
结果如下:
3、find
如果查找成功,该迭代器指向查找到的键值对;反之,则指向 map 容器最后一个键值对之后的位置(和 end() 成功方法返回的迭代器一样)。
std::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };
mapInfo[5] = "li";
std::map<int, string>::iterator mapIter = mapInfo.find(5);
if (mapIter != mapInfo.end())
{
std::cout << mapIter->first << " " << mapIter->second << std::endl;
}
结果如下:
4、若以上方法都不能获取到值,那只能遍历整个map容器查找,进而获取值
具体代码在这里就不写了
五、插入数据
前面已经说过,可以通过[]运算符修改或者添加键值对,在这里就不说这种用法了。
1、insert
insert方法是专门用来向 map 容器中插入新的键值对的。这里的"插入"指的是 insert() 方法可以将新的键值对插入到 map 容器中的指定位置。如果破坏了map容器的有序性,map容器会对新键值对的位置进行调整,也就是说,虽然insert可以将键值对插入指定的位置,但是插入之后map容器会检查插入的键值对是否符合有序性,不符合的话insert指定的位置就不是插入键值对真正的位置了。
1)不指定位置,直接插入
格式 | 说明 |
---|---|
pair<iterator,bool> insert (const value_type& val); | 引用传递一个键值对 |
template <class P> pair<iterator,bool> insert (P&& val); | 以右值引用的方式传递键值对 |
区别:传递参数的方式不同。无论是局部定义的键值对变量还是全局定义的键值对变量,都采用普通引用传递的方式;而对于临时的键值对变量,则以右值引用的方式传参。
std::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };
//格式1
std::pair<int, string> mapData = { 4, "wu" };
std::pair<std::map<int, string>::iterator, bool> ret;
ret = mapInfo.insert(mapData);
std::cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << std::endl;
//格式2
ret = mapInfo.insert({ 5,"ouyang" });
//等价于
//ret = mapInfo.insert(pair<int, string>{5, "ouyang"});
//ret = mapInfo.insert(make_pair(5, "ouyang"));
std::cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << std::endl;
//插入失败
ret = mapInfo.insert({ 1,"lu" });
std::cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << std::endl;
std::map<int, string>::iterator mapIter = mapInfo.begin();
for (; mapIter != mapInfo.end(); mapIter++)
{
std::cout << mapIter->first << " " << mapIter->second << std::endl;
}
结果如下:
由结果可知:
①返回值是一个 pair 对象,其中 pair.first 表示一个迭代器,pair.second 为一个 bool 类型变量:
如果成功插入 val,则该迭代器指向新插入的 val,bool 值为 true;
如果插入 val 失败,则表明当前 map 容器中存有和 val 的键相同的键值对(用 p 表示),此时返回的迭代器指向 p,bool 值为 false。
2)指定位置插入
格式 | 说明 |
---|---|
iterator insert (const_iterator position, const value_type& val); | 以普通引用的方式传递 val 参数 |
template <class P> iterator insert (const_iterator position, P&& val); | 以右值引用的方式传递 val 键值对参数 |
std::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };
//格式1
std::pair<int, string> mapData = { 4, "wu" };
std::map<int, string>::iterator mapIter = mapInfo.begin();
std::map<int, string>::iterator insertIter = mapInfo.insert(++mapIter, mapData);
std::cout << insertIter->first << " " << insertIter->second << std::endl;
//格式2
insertIter = mapInfo.insert(++mapIter, std::pair<int, string>(5, "kai"));
std::cout << insertIter->first << " " << insertIter->second << std::endl;
//插入失败
insertIter = mapInfo.insert(++mapIter, std::pair<int,string>(3,"ouyang"));
std::cout << insertIter->first << " " << insertIter->second << std::endl;
mapIter = mapInfo.begin();
for (; mapIter != mapInfo.end(); mapIter++)
{
std::cout << mapIter->first << " " << mapIter->second << std::endl;
}
结果如下:
由结果可知:
①和不指定位置的插入的方法的区别,这里返回的是迭代器
如果插入成功,insert() 方法会返回一个指向 map 容器中已插入键值对的迭代器;
如果插入失败,insert() 方法同样会返回一个迭代器,该迭代器指向 map 容器中和 val 具有相同键的那个键值对。
3)向当前 map 容器中插入其它 map 容器指定区域内的所有键值对
格式 |
---|
template <class InputIterator> void insert (InputIterator first, InputIterator last); |
std::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };
std::map<int, string> mapInfo2;
std::map<int, string>::iterator first = ++mapInfo.begin();
std::map<int, string>::iterator last = mapInfo.end();
mapInfo2.insert(first, last);
std::map<int, string>::iterator mapIter = mapInfo2.begin();
for (; mapIter != mapInfo2.end(); mapIter++)
{
std::cout << mapIter->first << " " << mapIter->second << std::endl;
}
结果如下:
由结果可知:
①需要其他map容器的开始和结束的迭代器,组成一个指定区域
4)一次向 map 容器中插入多个键值对
表列 A |
---|
void insert ({val1, val2, ...}); |
std::map<int, string> mapInfo;
mapInfo.insert({ {1,"test"},{2,"lin"},{3,"wei"} });
std::map<int, string>::iterator mapIter = mapInfo.begin();
for (; mapIter != mapInfo.end(); mapIter++)
{
std::cout << mapIter->first << " " << mapIter->second << std::endl;
}
结果如下:
insert的介绍就到这里,接下来讲讲比insert高效的方法
2、emplace
格式 |
---|
template <class... Args> pair<iterator,bool> emplace (Args&&... args); |
std::map<int, string> mapInfo;
pair<map<int, string>::iterator, bool> ret = mapInfo.emplace(1, "test");
std::cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << std::endl;
ret = mapInfo.emplace(2, "lin");
std::cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << std::endl;
ret = mapInfo.emplace(2, "kai");
std::cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << std::endl;
std::map<int, string>::iterator mapIter = mapInfo.begin();
for (; mapIter != mapInfo.end(); mapIter++)
{
std::cout << mapIter->first << " " << mapIter->second << std::endl;
}
结果如下:
由结果可知:
①使用emplace方法时,将创建新键值对所需的数据作为参数直接传入即可,返回值是一个pair对象,和不指定位置的insert方法的返回值一样
3、emplace_hint
格式 |
---|
template <class... Args> iterator emplace_hint (const_iterator position, Args&&... args); |
该方法不仅要传入创建键值对所需要的数据,还需要传入一个迭代器作为第一个参数,指明要插入的位置。
std::map<int, string> mapInfo;
map<int, string>::iterator iter = mapInfo.emplace_hint(mapInfo.begin(), 1, "test");
std::cout << iter->first << " " << iter->second << std::endl;
iter = mapInfo.emplace_hint(mapInfo.begin(), 2, "lin");
cout << iter->first << " " << iter->second << endl;
iter = mapInfo.emplace_hint(mapInfo.begin(), 2, "kai");
cout << "insert 2 kai finial " << iter->first << " " << iter->second << endl;
std::map<int, string>::iterator mapIter = mapInfo.begin();
for (; mapIter != mapInfo.end(); mapIter++)
{
std::cout << mapIter->first << " " << mapIter->second << std::endl;
}
结果如下:
①返回值是一个迭代器。当成功插入新键值对时,返回的迭代器指向新插入的键值对;反之,如果插入失败,则表明 map 容器中存有相同键的键值对,返回的迭代器就指向这个键值对
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。