概述
map
和multimap
是C++ STL中的关联容器,它们存储的是键值对(key-value pairs),并且会根据键(key)自动排序。两者的主要区别在于:
map
不允许重复的键multimap
允许重复的键
本文将详细解析示例代码中涉及的map
操作,包括赋值 、排序 、大小查询 和删除等核心功能。
1. 头文件与命名空间
cpp
#include <iostream>
#include <map>
using namespace std;
#include <map>
:必须包含的头文件,提供map
和multimap
的实现using namespace std
:使用标准命名空间,避免每次都要写std::
2. 自定义排序规则(仿函数)
cpp
class CompareInt {
public:
bool operator()(const int& left, const int& right) const {
return left > right; // 降序排序
}
};
- 仿函数(Functor) :重载了
()
运算符的类,可以像函数一样调用 - 这里实现了降序排序 规则,当
left > right
时返回true
- 注意
operator()
应该声明为const
,因为它不修改对象状态
3. map的声明与初始化
cpp
map<int, string> mapStu; // 默认less 升序排序
//map<int, string,greater<int>> mapStu; // greater 降序排序
//map<int, string,CompareInt> mapStu; // 使用自定义仿函数
- 默认排序 :不指定第三个模板参数时,使用
less<Key>
,即升序排序 - 内置排序规则 :可以使用
greater<Key>
实现降序排序 - 自定义排序:通过传递自定义的仿函数类型作为第三个模板参数
4. 插入元素
cpp
mapStu.insert(pair<int, string>(2, "小明"));
mapStu.insert(pair<int, string>(3, "廉颇"));
mapStu.insert(pair<int, string>(1, "妲己"));
mapStu.insert(pair<int, string>(4, "庄周"));
- insert():插入键值对
- 使用
pair
构造键值对,first
是键,second
是值 - 插入后元素会根据键自动排序
5. 拷贝构造与赋值
cpp
map<int, string> mapB(mapStu); // 拷贝构造
map<int, string> mapC = mapStu; // 赋值操作
- 拷贝构造:创建一个新map并复制所有元素
- 赋值操作:将已有map的所有元素复制到另一个map
- 两种方式都会创建与原map完全相同的新容器
6. 元素访问与修改
cpp
mapC[3] = "小乔"; // 通过键访问并修改值
- operator[]:通过键访问对应的值
- 如果键不存在,会自动插入该键,值为默认构造
7. 交换操作
cpp
mapC.swap(mapB); // 交换两个map的内容
- swap():高效交换两个map的内容
- 实际只交换内部指针,不复制元素,时间复杂度O(1)
8. 删除操作
8.1 删除区间元素
cpp
map<int, string>::iterator iBegin = mapB.begin();
++iBegin;
map<int, string>::iterator iEnd = mapB.end();
mapB.erase(iBegin, iEnd); // 删除[iBegin, iEnd)区间
- erase(beg, end) :删除迭代器区间
[beg, end)
内的元素 - 区间是半闭半开 的,包含
beg
但不包含end
- 返回void(新标准返回下一个元素的迭代器)
8.2 删除单个元素
cpp
mapC.erase(mapC.begin()); // 删除第一个元素
mapC.erase(4); // 删除键为4的元素
- erase(pos) :删除迭代器
pos
指向的元素 - erase(key) :删除所有键等于
key
的元素(对于map
最多一个)
8.3 清空容器
cpp
mapC.clear(); // 清空所有元素
- clear():删除容器中的所有元素,使size为0
8.4 删除结果检查
cpp
map<int, string, greater<int>>::size_type st = mapStu.erase(5);
cout << "st = " << st << endl; // 输出删除的元素个数
- **erase(key)**返回删除的元素个数
- 对于
map
,返回值只能是0或1 - 对于
multimap
,返回值可以是任意非负整数
9. 大小查询
cpp
if (!mapC.empty()) {
cout << "mapC的大小: " << mapC.size() << endl;
}
- empty():检查容器是否为空
- size():返回容器中元素的个数
- 通常先检查
empty()
再调用size()
更安全
10. 迭代器遍历
cpp
for (map<int, string, CompareInt>::iterator it = mapStu.begin();
it != mapStu.end(); it++) {
cout << "key: " << (*it).first << " value: " << (*it).second << endl;
}
- begin()/end():获取首元素和尾后迭代器
- 迭代器解引用得到
pair<const Key, Value>
- 可以用
it->first
和it->second
访问键和值
完整代码回顾
cpp
#include <iostream>
#include <map>
using namespace std;
// 仿函数用于比较int(降序排序)
class CompareInt {
public:
bool operator()(const int& left, const int& right) const {
return left > right; // 降序排序
}
};
int main(void) {
map<int, string> mapStu; // 默认less 升序排序
//map<int, string,greater<int>> mapStu; // greater 降序排序
// 使用自定义的仿函数作为比较器
//map<int, string,CompareInt> mapStu;
mapStu.insert(pair<int, string>(2, "小明"));
mapStu.insert(pair<int, string>(3, "廉颇"));
mapStu.insert(pair<int, string>(1, "妲己"));
mapStu.insert(pair<int, string>(4, "庄周"));
// map对象的拷贝构造与赋值
map<int, string> mapB(mapStu); // 拷贝构造
for (map<int, string>::iterator it = mapB.begin(); it != mapB.end(); it++) {
cout << "key: " << (*it).first << " value: " << (*it).second << endl;
}
cout << endl;
map<int, string> mapC = mapStu; // 赋值
for (map<int, string>::iterator it = mapC.begin(); it != mapC.end(); it++) {
cout << "key: " << (*it).first << " value: " << (*it).second << endl;
}
cout << endl;
mapC[3] = "小乔";
mapC.swap(mapB);
// map的删除
map<int, string>::iterator iBegin = mapB.begin();
++iBegin;
map<int, string>::iterator iEnd = mapB.end();
mapB.erase(iBegin, iEnd); // 删除区间
mapC.erase(mapC.begin()); // 删除第一个元素
mapC.erase(4); // 删除key为4的元素
mapC.clear(); // 清空容器
map<int, string, greater<int>>::size_type st = mapStu.erase(5);
cout << "st = " << st << endl; // 输出删除个数
// map的大小
if (!mapC.empty()) {
cout << "mapC的大小: " << mapC.size() << endl;
}
// 遍历map
for (map<int, string, CompareInt>::iterator it = mapStu.begin();
it != mapStu.end(); it++) {
cout << "key: " << (*it).first << " value: " << (*it).second << endl;
}
system("pause");
return 0;
}