当前位置: 首页 > news >正文

C++:map容器

前言:在 C++ STL 中,map是一种关联容器,用于存储键值对(key-value) 数据,并且会根据键(key)自动排序。它的核心特点是键唯一按键有序,非常适合需要通过键快速查找、插入和删除值的场景。


1. map 的核心特性

  • 键值对存储:每个元素是一个pair<const Key, Value>结构,包含一个键(key)和一个值(value)。
  • 键的唯一性:同一个键只能出现一次,插入重复键会被忽略(或覆盖,取决于用法)。
  • 自动排序:元素会按照键的大小自动排序(默认升序),排序规则可自定义。
  • 底层实现:通常基于红黑树(自平衡二叉搜索树),因此插入、删除、查找操作的时间复杂度均为 O(log n)
  • 迭代器支持:提供双向迭代器,可遍历元素,但不能随机访问(如it + 2不允许)。

2. 头文件与定义

使用map需包含头文件 <map>,并使用std命名空间:

#include <map>
using namespace std;// 定义一个默认map(键为int,值为string,按key升序)
map<int, string> m;// 定义一个按key降序排列的map
map<int, string, greater<int>> m_desc;

map的模板参数说明:

  • 第一个参数:键(key)的类型(如int
  • 第二个参数:值(value)的类型(如string
  • 第三个参数(可选):比较器类型(默认less<Key>,即升序)

3. 常用操作

(1)插入元素

有多种插入方式,最常用的是insert()和直接赋值:

map<int, string> m;// 方式1:insert()插入pair对象
m.insert(pair<int, string>(1, "apple"));// 方式2:insert()插入make_pair(更简洁)
m.insert(make_pair(2, "banana"));// 方式3:直接赋值(若key已存在,会覆盖原有value)
m[3] = "pear";// 方式4:C++11及以上,插入初始化列表
m.insert({{4, "orange"}, {5, "grape"}});// 插入重复key(会被忽略)
auto result = m.insert(make_pair(1, "cherry"));
if (!result.second) {cout << "键1已存在,值为:" << result.first->second << endl;
}

insert()返回值是pair<iterator, bool>

  • 第一个元素:指向插入位置的迭代器
  • 第二个元素:true表示插入成功,false表示 key 已存在

(2)访问元素

  • 通过[key]访问:若 key 不存在,会自动插入一个默认值(如空字符串、0 等)。
  • 通过at(key)访问:若 key 不存在,会抛出out_of_range异常(更安全)。
  • 通过迭代器访问:遍历或定位元素时使用。
map<int, string> m = {{1, "apple"}, {2, "banana"}, {3, "pear"}};// 方式1:[key]访问(可能自动插入新元素)
cout << m[2] << endl; // 输出:banana
cout << m[4] << endl; // 键4不存在,插入默认值(空字符串)// 方式2:at(key)访问(安全检查)
try {cout << m.at(3) << endl; // 输出:pearcout << m.at(5) << endl; // 抛出异常
} catch (const out_of_range& e) {cout << "访问失败:" << e.what() << endl;
}// 方式3:迭代器访问
auto it = m.find(1);
if (it != m.end()) {cout << "键" << it->first << "的值是:" << it->second << endl;
}

(3)删除元素

  • erase(key):删除键为key的元素,返回删除的元素个数(0 或 1)。
  • erase(pos):删除迭代器pos指向的元素,无返回值。
  • erase(begin, end):删除迭代器范围[begin, end)内的元素,无返回值。
  • clear():清空所有元素。
map<int, string> m = {{1, "apple"}, {2, "banana"}, {3, "pear"}};// 删除键为2的元素
m.erase(2); // 删除第一个元素
auto it = m.begin();
m.erase(it); // 清空map
m.clear();

(4)查找元素

  • find(key):查找键为key的元素,返回指向该元素的迭代器;若不存在,返回end()
  • count(key):返回键为key的元素个数(由于键唯一,结果只能是 0 或 1)。
  • lower_bound(key):返回第一个键大于等于key的元素迭代器。
  • upper_bound(key):返回第一个键大于key的元素迭代器。
map<int, string> m = {{1, "apple"}, {3, "banana"}, {5, "pear"}};// 查找键3
auto it = m.find(3);
if (it != m.end()) {cout << "找到:" << it->first << " → " << it->second << endl;
}// 检查键2是否存在
if (m.count(2) == 0) {cout << "键2不存在" << endl;
}// 查找第一个键>=4的元素(指向5)
auto it_low = m.lower_bound(4);// 查找第一个键>3的元素(指向5)
auto it_high = m.upper_bound(3);

(5)遍历元素

通过迭代器遍历,由于元素按键排序,遍历结果会按键的顺序输出:

map<int, string> m = {{3, "pear"}, {1, "apple"}, {2, "banana"}};// 正向遍历(按key升序)
for (auto it = m.begin(); it != m.end(); ++it) {// first是键,second是值cout << it->first << " → " << it->second << endl;
}
// 输出:1→apple  2→banana  3→pear// C++11及以上:范围for循环
for (const auto& pair : m) {cout << pair.first << " → " << pair.second << endl;
}// 反向遍历(按key降序)
for (auto it = m.rbegin(); it != m.rend(); ++it) {cout << it->first << " → " << it->second << endl;
}
// 输出:3→pear  2→banana  1→apple

(6)其他常用方法

  • size():返回键值对的数量。
  • empty():判断 map 是否为空(空则返回true)。
  • swap(other_map):与另一个 map 交换内容。
map<int, string> m = {{1, "a"}, {2, "b"}};
cout << "元素数量:" << m.size() << endl; // 输出:2if (!m.empty()) {cout << "map不为空" << endl;
}map<int, string> m2;
m.swap(m2); // m变空,m2包含原m的元素

4. 自定义键类型与排序规则

map的键是自定义类型时,需要指定排序规则(通过比较器)。

示例:用map存储学生信息,按学号降序排列

#include <map>
#include <string>
#include <iostream>
using namespace std;// 自定义键类型:学生学号
class StudentID {
public:int grade; // 年级int num;   // 学号StudentID(int g, int n) : grade(g), num(n) {}
};// 自定义比较器:按年级降序,年级相同则按学号降序
class CompareID {
public:bool operator()(const StudentID& a, const StudentID& b) const {if (a.grade != b.grade) {return a.grade > b.grade; // 年级高的在前}return a.num > b.num; // 年级相同,学号大的在前}
};int main() {// 键为StudentID,值为学生姓名,比较器为CompareIDmap<StudentID, string, CompareID> students;students.insert({ StudentID(3, 101), "Alice" });students.insert({ StudentID(2, 202), "Bob" });students.insert({ StudentID(3, 103), "Charlie" });// 遍历输出(按年级降序:3年级 → 2年级)for (const auto& pair : students) {cout << "年级:" << pair.first.grade<< ",学号:" << pair.first.num<< ",姓名:" << pair.second << endl;}return 0;
}

输出结果:

年级:3,学号:103,姓名:Charlie
年级:3,学号:101,姓名:Alice
年级:2,学号:202,姓名:Bob

5. 与 unordered_map 的区别

特性mapunordered_map
底层实现红黑树哈希表
排序按键自动排序无序
查找效率O(log n)平均 O (1),最坏 O (n)
内存占用较低(红黑树结构紧凑)较高(哈希表需预留空间)
适用场景需要有序遍历或范围查询追求极致查找效率

6. 注意事项

  • map的键是常量const Key),不能直接修改(会破坏排序),若需修改键,需先删除旧键值对,再插入新的。
  • 使用[key]访问时,若键不存在会自动插入默认值,可能导致意外行为(如需避免,可用find()at())。
  • 迭代器在插入和删除操作后,只有被删除元素的迭代器失效,其他迭代器仍然有效。

总结:map是 STL 中处理键值对数据的重要容器,其有序性和高效的查找能力使其在需要通过键快速定位值的场景中(如字典、索引表等)非常实用。掌握map的用法,能帮助你更高效地处理关联数据。


文章转载自:

http://DdU048TO.pzdxg.cn
http://Qev0i9nR.pzdxg.cn
http://upGSYrqb.pzdxg.cn
http://rHTZmcqE.pzdxg.cn
http://SIewX0pj.pzdxg.cn
http://izBY8DMS.pzdxg.cn
http://JHSahrf0.pzdxg.cn
http://VPSbkUkO.pzdxg.cn
http://I9fLuQt1.pzdxg.cn
http://Qn84ftCz.pzdxg.cn
http://UlK0ejDF.pzdxg.cn
http://txFvWfdZ.pzdxg.cn
http://s041tmer.pzdxg.cn
http://QclHEquy.pzdxg.cn
http://e6rfb5SH.pzdxg.cn
http://McaTxzGC.pzdxg.cn
http://jQjp57uV.pzdxg.cn
http://8jmc59Up.pzdxg.cn
http://l5210GYP.pzdxg.cn
http://YCAICTTk.pzdxg.cn
http://DJEkZz11.pzdxg.cn
http://Jl7JTRmS.pzdxg.cn
http://5TQ2V5Yi.pzdxg.cn
http://PaG5aAgw.pzdxg.cn
http://ob4guvEN.pzdxg.cn
http://iBq0Cw24.pzdxg.cn
http://i5AGjNJe.pzdxg.cn
http://Czh2NtA2.pzdxg.cn
http://vsmY5ojV.pzdxg.cn
http://AugItvCy.pzdxg.cn
http://www.dtcms.com/a/380777.html

相关文章:

  • Java内存模型与线程私有共享区域与直接内存的理解
  • MCP专题五、MCP 的未来趋势与展望
  • SIFT特征匹配实战:KNN算法实现指纹认证
  • ETL 不只是数据搬运工:如何实现智能转换与清洗?
  • UDP套接字的使用
  • 【Vue2手录11】Vue脚手架(@vue_cli)详解(环境搭建+项目开发示例)
  • Vue 使用docx-preview,渲染word后,继续其他操作(word中内容相关)的实现
  • [优选算法专题二——NO.16最小覆盖子串]
  • Nginx生产级优化配置全解析和配置原因解析
  • 14自由度汽车动力学模型
  • FS950R08A6P2B 双通道汽车级IGBT模块Infineon英飞凌 电子元器件核心解析
  • 交换机协议栈FRR中使用
  • C++ 二叉搜索树的详解与实现
  • 记录:离线部署
  • python逆向-逆向pyinstaller打包的exe程序反编译获取源代码
  • 最大连续 1 的个数
  • LVS负载均衡群集和LVS+Keepalived群集
  • 嵌入式开发:中断配置全解析
  • 【Vue3】07-利用setup编写vue(2)-setup的语法糖
  • 使用 信号量(Semaphore) 来控制异步任务并发数
  • 1688 商品 API 实战指南:B2B 场景下的合规对接与批量运营方案
  • Qt Bridge for Figma
  • 解决docker配置了镜像源但还会拉取官方镜像源的问题
  • 【JavaEE】网络原理初识
  • 操作系统应用开发(七)mac苹果模拟器——东方仙盟练气期
  • PBI Plus 技术解析:全渠道协同架构下的数据协作效率提升方案​
  • 【C#】三个特殊的 Caller Info Attributes
  • LangChain4j入门学习
  • Django ORM 模型
  • 【SpringBoot】——原理篇