一、map 简介
Map是STL的一个容器,它提供一对一的hash。元素是以键的升序排列的,因为 map 中默认使用 less 函数对象对它们进行排序。
一个map变量中的值以pair的形式存在,可以有多个pair,每个pair中存储两个值。
- 第一个为关键字key,每个key只能在map中出现一次,类似数据库中的主键,可以为key指定不同的类型;
- 第二个为key对应的值value,二者是一对一的关系,不同的key值可以对应相同的value,可以为key指定不同的类型。
二、map的三种插入方法对比
根据调用的插入函数不同,有三种方式插入map元素:
方式 | 函数 | key值已存在时是否会覆盖原value值 |
方法一 | insert() | 不会覆盖 |
方法二 | emplace() | 不会覆盖 |
方法四 | operator[ ] | 会覆盖 |
三种方法的区别:
- operator[] 与 insert() 的区别主要是,在 map 中已有 key 时,insert() 不会修改 map,而 operator[] 会更新 map 中 key 对应的 value。
- insert() 与 emplace() 的主要区别是,insert() 先在某个位置新建一个 value_type (在 map 中,这是一个pair),然后根据 key 是否重复,来判断是否插入到 map,而 emplace() 是直接在 map 中新建一个 pair ,然后根据 key 是否重复,来判断是否从 map 中销毁。
- 通常情况下,emplace() 比 insert() 快,因为减少了对象的创建与移动。
- 使用 operator[] 时,value 类型需要默认的构造函数。m[1] = value1; 这行代码在执行时,会先使用默认值构造 m[1],然后对 key 赋值。
根据insert()参数的类型不同,insert(),emplace()又有三种方式插入map元素:
方式 | 函数 |
方法一 | pair |
方法二 | make_pair |
方法三 | value_type |
1. insert() 用法举例:
<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">std::map<std:: string,size_t> people;
// 1.
people.insert(std::pair<const std::string, size_t> {"Bill", 48});
people.insert(std::pair<const std::string, size_t>("Billx", 48));
people.insert({"Bill", 48});
// 2.
people.insert(std::make_pair("Bill", 48)); // make_pair<>() 函数模板的类型参数是从参数类型推断出来的;
people.insert(std::make_pair<std:: string, size_t> (std:: string {"Bill"},48)); // 不依靠隐式转换,z指定类型的 pair 对象
// 3.
people.insert(map< std::string, size_t>::value_type ("Bill", 48));
</code></span></span>
2. emplace() 用法举例:
<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp"> std::map<std::string, size_t> people;
// 1.
people.emplace("c", 48); // uses pair's template constructor
// 2.
people.emplace(std::make_pair(std::string("a"), 48)); // uses pair's move constructor
people.emplace(std::make_pair("b", 48)); //uses pair's converting move constructor
// 3.
people.emplace(std::piecewise_construct, std::forward_as_tuple("d"), std::forward_as_tuple(10)); // uses pair's piecewise constructor
</code></span></span>
3. operator[ ]用法举例:
<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">people["Bill"]= 48;
</code></span></span>
三、代码测试
<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<int, string> map_;
/*insert返回值为pair 原型:typedef pair<iterator, bool> _Pairib
pair->first=iterator,pair->second=bool;如果插入成功bool=true,失败则flase*/
/*1、pair插入*/
pair<map<int, string>::iterator, bool> insert_ok = map_.insert(pair<int, string>(11, "pair"));
// 判断插入是否成功
if (insert_ok.second == true) {
cout << "新值插入成功!" << endl;
} else {
cout << "新值插入失败!" << endl;
}
/*若key值相同,insert方式插入是否成功*/
pair<map<int, string>::iterator, bool> insert_false = map_.insert(pair<int, string>(11, "pair_repeat"));
// 判断插入是否成功
if (insert_false.second == true) {
cout << "重复值插入成功!" << endl;
} else {
cout << "重复值插入失败!" << endl;
}
/*2、make_pair插入*/
map_.insert(make_pair(22, "make_pair"));
map_.insert(make_pair(22, "make_pair_repeat"));
/*3.value_type插入*/
map_.insert(map<int, string>::value_type(33, "value_type"));
map_.insert(map<int, string>::value_type(33, "value_type_repeat"));
/*4.[]插入*/
map_[44] = "[]";
map_[44] = "[]_repeat";
/*输出测试结果*/
for (map<int, string>::iterator it = map_.begin(); it != map_.end(); it++) {
cout << it->first << ",\t" << it->second << endl;
}
cout << "……………………………………" << endl;
/*删除map*/
cout << "正在删除……" << endl;
while (!map_.empty()) {
map<int, string>::iterator it = map_.begin();
cout << it->first << ",\t" << it->second << endl;
map_.erase(it);
}
return 0;
}
</code></span></span>
测试结果如下图:
四、如何修改指定key对应的value
1. 使用insert()
成员函数 insert() 会返回一个 pair<iterator,bool> 对象。对象的成员 first 是一个迭代器,它要么指向插入元素,要么指向阻止插入的元素。这个对象的成员变量 second (布尔型)是返回对象,如果插入成功,返回值为 true,否则为 false。
如果 map 中已经保存了一个和这个键相同的对象,则插入失败返回指向阻止插入的元素。
当元素已经存在时,如果想将键值“Bill”对应的年龄值改为 48,可以像下面这样使用 insert() 返回的 pair 对象来做到这一点:
<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">ret_pr = people.insert(std::make_pair("Bill", 38));
if(!ret_pr.second) // 元素("Bill", xxx)已经存在
ret_pr.first—>second = 48; //改value值
</code></span></span>
如果不确定元素是否存在,而且仍然想使用插入符,可以使用map 中的 count() 函数,它会返回 map 中指定键对应元素的数目,这个数目可能是 0 或 1。
<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">if (!people.count("Ian")) // 元素如果不存在,则插入
people.insert (ret_pr.first, std::make_pair ("Ian", 38));
</code></span></span>
2. 使用operator[]
operator[] 不论元素存在与否,都会将指定值插入到map,如果相同key的元素已经存在,则将value值替换。
<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">std::map<std::string, size_t> people;
people["Bill"]= 48;
people["Bill"]= 50; // 将{"Bill",48}替换为{"Bill",50}</code></span></span>