C++ STL map
文章目录
- C++ STL `map` 详解
- 1. `std::map` 的特性
- 2. 包含头文件
- 3. 声明和初始化 `std::map`
- 4. 常用成员函数
- 4.1 元素访问
- 4.2 容量
- 4.3 修改容器
- 4.4 查找元素
- 4.5 遍历映射
- 4.6 其他常用函数
- 5. 使用示例
- 6. 注意事项
- 7. 与其他关联容器的比较
- 总结
C++ STL map
详解
在 C++ 标准模板库(STL)中,std::map
是一种关联容器,用于存储键值对(key-value pairs),其中每个键在容器中是唯一的。std::map
基于平衡二叉树(通常是红黑树)实现,提供了高效的查找、插入和删除操作。下面将详细介绍 std::map
的特性、常用成员函数以及使用示例。
1. std::map
的特性
- 键值对存储:每个元素都是一个键值对,形式为
std::pair<const Key, T>
,其中Key
是键的类型,T
是值的类型。 - 唯一键:容器中的每个键都是唯一的,不能有重复的键。
- 有序存储:元素按键的顺序自动排序,默认是升序。也可以自定义比较函数来改变排序方式。
- 底层实现:通常基于平衡二叉树(如红黑树)实现,保证了操作的对数时间复杂度。
- 不允许修改键:由于键用于维护内部结构,
std::map
不允许修改已存在元素的键。
2. 包含头文件
使用 std::map
需要包含 <map>
头文件:
#include <map>
3. 声明和初始化 std::map
#include <map>
#include <string>
#include <iostream>
int main() {
// 声明一个空的整数到字符串的映射
std::map<int, std::string> ageMap;
// 使用初始化列表声明并初始化映射
std::map<std::string, int> scoreMap = {
{"Alice", 90},
{"Bob", 85},
{"Charlie", 95}
};
// 声明一个具有相同键值对的映射
std::map<std::string, int> anotherScoreMap(scoreMap);
return 0;
}
4. 常用成员函数
4.1 元素访问
operator[]
:通过键访问对应的值。如果键不存在,则插入该键并赋予默认值。at(const Key& key)
:通过键访问对应的值。如果键不存在,抛出std::out_of_range
异常。
std::map<std::string, int> scoreMap = {{"Alice", 90}, {"Bob", 85}};
// 使用 operator[]
std::cout << "Alice 的分数: " << scoreMap["Alice"] << std::endl; // 输出 90
scoreMap["Charlie"] = 95; // 插入新键值对
// 使用 at()
try {
std::cout << "Bob 的分数: " << scoreMap.at("Bob") << std::endl; // 输出 85
std::cout << "David 的分数: " << scoreMap.at("David") << std::endl; // 抛出异常
} catch (const std::out_of_range& e) {
std::cerr << "异常: " << e.what() << std::endl;
}
4.2 容量
empty()
:检查映射是否为空。size()
:返回映射中的元素数量。max_size()
:返回映射可能包含的最大元素数量。
if (scoreMap.empty()) {
std::cout << "scoreMap 为空。" << std::endl;
} else {
std::cout << "scoreMap 大小: " << scoreMap.size() << std::endl; // 输出 3
}
4.3 修改容器
insert(const value_type& value)
或emplace(Args&&... args)
:插入元素。erase(iterator position)
或erase(const Key& key)
:移除元素。clear()
:移除所有元素。
// 插入元素
scoreMap.insert({"David", 88});
scoreMap.emplace("Eve", 92);
// 通过键删除元素
scoreMap.erase("Bob");
// 通过迭代器删除元素
auto it = scoreMap.find("Alice");
if (it != scoreMap.end()) {
scoreMap.erase(it);
}
// 清空映射
scoreMap.clear();
4.4 查找元素
find(const Key& key)
:返回指向键的迭代器,如果键不存在,则返回map.end()
。count(const Key& key)
:返回键出现的次数(对于std::map
来说,只能是 0 或 1)。
if (scoreMap.find("Alice") != scoreMap.end()) {
std::cout << "找到 Alice。" << std::endl;
} else {
std::cout << "未找到 Alice。" << std::endl;
}
if (scoreMap.count("Bob") > 0) {
std::cout << "找到 Bob。" << std::endl;
} else {
std::cout << "未找到 Bob。" << std::endl;
}
4.5 遍历映射
可以使用迭代器或范围-based for 循环(C++11 及以上)来遍历 std::map
。
for (const auto& pair : scoreMap) {
std::cout << pair.first << " 的分数: " << pair.second << std::endl;
}
// 使用迭代器
for (auto it = scoreMap.begin(); it != scoreMap.end(); ++it) {
std::cout << it->first << " 的分数: " << it->second << std::endl;
}
4.6 其他常用函数
lower_bound(const Key& key)
:返回指向第一个不小于给定键的元素的迭代器。upper_bound(const Key& key)
:返回指向第一个大于给定键的元素的迭代器。equal_range(const Key& key)
:返回一对迭代器,表示等于给定键的所有元素范围(对于std::map
来说,最多只有一个元素)。swap(map& other)
:交换两个映射的内容。
// 插入一些元素
scoreMap["Alice"] = 90;
scoreMap["Bob"] = 85;
scoreMap["Charlie"] = 95;
// 使用 lower_bound
auto low = scoreMap.lower_bound("Bob");
if (low != scoreMap.end()) {
std::cout << "第一个不小于 Bob 的键: " << low->first << std::endl;
}
// 使用 upper_bound
auto up = scoreMap.upper_bound("Bob");
if (up != scoreMap.end()) {
std::cout << "第一个大于 Bob 的键: " << up->first << std::endl;
}
// 使用 equal_range
auto range = scoreMap.equal_range("Charlie");
if (range.first != range.second) {
std::cout << "找到 Charlie 的分数: " << range.first->second << std::endl;
}
// 交换两个映射
std::map<std::string, int> anotherMap = {{"Dave", 80}};
scoreMap.swap(anotherMap);
5. 使用示例
下面给出一个综合示例,展示如何使用 std::map
进行基本操作:
#include <iostream>
#include <map>
#include <string>
int main() {
// 创建并初始化映射
std::map<std::string, int> inventory = {
{"苹果", 50},
{"香蕉", 30},
{"橘子", 20}
};
// 输出初始库存
std::cout << "初始库存:" << std::endl;
for (const auto& item : inventory) {
std::cout << item.first << ": " << item.second << std::endl;
}
// 添加新商品
inventory["葡萄"] = 40;
std::cout << "\n添加葡萄后:" << std::endl;
for (const auto& item : inventory) {
std::cout << item.first << ": " << item.second << std::endl;
}
// 更新商品数量
inventory["香蕉"] = 35;
std::cout << "\n更新香蕉数量后:" << std::endl;
for (const auto& item : inventory) {
std::cout << item.first << ": " << item.second << std::endl;
}
// 删除商品
inventory.erase("橘子");
std::cout << "\n删除橘子后:" << std::endl;
for (const auto& item : inventory) {
std::cout << item.first << ": " << item.second << std::endl;
}
// 查找商品
std::string searchItem = "苹果";
if (inventory.find(searchItem) != inventory.end()) {
std::cout << "找到 " << searchItem << ",数量: " << inventory[searchItem] << std::endl;
} else {
std::cout << "未找到 " << searchItem << std::endl;
}
// 遍历并打印所有商品
std::cout << "所有库存商品:" << std::endl;
for (const auto& item : inventory) { // 替换结构化绑定
std::cout << item.first << ": " << item.second << std::endl;
}
return 0;
}
输出:
6. 注意事项
-
键的唯一性:
std::map
中的每个键都是唯一的,插入重复的键会覆盖原有的值。 -
有序性:元素按键自动排序,默认是升序。可以通过自定义比较函数改变排序方式。
struct Compare { bool operator()(const std::string& a, const std::string& b) const { return a > b; // 降序排列 } }; std::map<std::string, int, Compare> descendingMap = {{"apple", 1}, {"banana", 2}}; // descendingMap 将按降序排列键
-
性能:
std::map
的插入、删除和查找操作的时间复杂度为 O(log n),适用于需要有序存储且频繁查找的场景。 -
内存开销:相比
std::unordered_map
,std::map
通常有更高的内存开销,因为它需要维护元素的顺序。
7. 与其他关联容器的比较
特性 | std::map | std::unordered_map | std::multimap |
---|---|---|---|
键的唯一性 | 唯一 | 唯一 | 允许重复键 |
排序 | 有序(默认升序) | 无序 | 有序(默认升序) |
底层实现 | 平衡二叉树(如红黑树) | 哈希表 | 平衡二叉树(如红黑树) |
查找时间复杂度 | O(log n) | 平均 O(1),最坏情况 O(n) | O(log n) |
插入/删除时间复杂度 | O(log n) | 平均 O(1),最坏情况 O(n) | O(log n) |
元素遍历顺序 | 按键排序 | 无特定顺序 | 按键排序 |
根据具体需求选择合适的关联容器。例如,如果需要快速查找且不关心元素的顺序,std::unordered_map
是更好的选择;如果需要元素有序存储,std::map
更为合适。
总结
std::map
是 C++ STL 中一个功能强大的关联容器,适用于需要存储键值对且键唯一的场景。它提供了高效的查找、插入和删除操作,并自动维护元素的有序性。了解其特性和常用成员函数,可以帮助我们更高效地编写代码。在实际应用中,应该根据具体需求选择最合适的容器类型。
当然,map容器除了这些之外,还有其他的用法,可以在实践的过程中逐渐摸索,及时记录,便于之后的工作。
原文地址:https://blog.csdn.net/2503_91044785/article/details/146323083
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/589600.html 如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/589600.html 如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!