C++ 中的 std::map
是标准库中的一种关联容器,它提供了一种键值对的存储方式,其中键是唯一的,并且按照升序排序。以下是对 std::map
的详细用法总结:
#include
using namespace std;
// 声明一个 map,键为 string 类型,值为 int 类型
map<string, int> myMap;
// 直接初始化
map<string, int> myMap2 = {
{"Alice", 85},
{"Bob", 90},
{"Charlie", 95}
};
// 插入单个键值对
myMap["David"] = 88;
// 使用 insert 方法插入
pair<map<string, int>::iterator, bool> result = myMap.insert({"Eve", 92});
// 查找键
auto it = myMap.find("Alice");
if (it != myMap.end()) {
cout << "Alice's grade: " << it->second << endl;
} else {
cout << "Alice not found." << endl;
}
// 使用 at() 获取值,若键不存在则抛出异常
try {
cout << "Charlie's grade: " << myMap.at("Charlie") << endl;
} catch (const out_of_range&) {
cout << "Charlie not found." << endl;
}
// 删除指定键的元素
myMap.erase("Alice");
// 删除迭代器指向的元素
auto it2 = myMap.find("Bob");
if (it2 != myMap.end()) {
myMap.erase(it2);
}
// 使用迭代器遍历
for (auto it = myMap.begin(); it != myMap.end(); ++it) {
cout << it->first << ": " << it->second << endl;
}
// 使用范围for循环遍历
for (const auto& entry : myMap) {
cout << entry.first << ": " << entry.second << endl;
}
size()
:返回 map 中元素的数量。empty()
:如果 map 为空则返回 true
,否则返回 false
。clear()
:清空 map 内的所有元素。count(key)
:返回 key 出现的次数(对于 map 总是 0 或 1,因为键是唯一的)。lower_bound(key)
和 upper_bound(key)
:返回指向首个大于等于(小于)key的元素的迭代器。// 更新已有键的值
myMap["David"] = 90;
erase()
返回的新迭代器。以上总结了C++中 std::map
关键用法,实际使用时应根据具体需求选择合适的方法操作。
equal_range
查找键值范围equal_range
函数返回一个迭代器对,该对包含 map 中与给定键相等的所有元素的范围(对于 map,始终只有一个元素)。这对于在已排序的键值对中查找键值范围特别有用。
auto range = myMap.equal_range("Bob");
for (auto it = range.first; it != range.second; ++it) {
cout << it->first << ": " << it->second << endl;
}
emplace
添加元素emplace
函数可以在 map 中直接构造(而不是拷贝或移动)元素,从而节省时间和空间。它接受与 map 键值对类型相同的参数。
myMap.emplace("Frank", 93); // 直接在map中构造新的键值对
cbegin
和 cend
获取常量迭代器当你需要在不影响 map 的情况下遍历其元素时,可以使用 cbegin()
和 cend()
获取常量迭代器。
for (const auto& entry : myMap) {
// 使用常量引用,不会修改 map 中的元素
}
// 或者使用常量迭代器
for (auto it = myMap.cbegin(); it != myMap.cend(); ++it) {
// ...
}
默认情况下,std::map
的键按照 <
运算符进行排序。如果要使用其他比较函数,可以提供一个自定义的比较器。
struct CustomComparator {
bool operator()(const std::string& a, const std::string& b) const {
return a.length() < b.length(); // 按字符串长度排序
}
};
std::map<std::string, int, CustomComparator> myCustomMap;
multimap
存储重复键std::multimap
类似于 std::map
,但允许有重复的键,每个键可以关联多个值。
总之,C++ std::map
提供了丰富的功能,支持高效的键值对存储和检索,尤其适合那些需要根据键排序并保持唯一性的场景。通过熟练掌握上述用法,你可以更好地利用这一强大工具。
除了使用 find
函数检查键是否存在之外,也可以直接使用 count
函数。count
函数返回键在 map 中出现的次数,对于 map 来说,如果键存在则返回1,否则返回0。
if (myMap.count("Alice") > 0) {
cout << "Alice is in the map." << endl;
} else {
cout << "Alice is not in the map." << endl;
}
begin()
返回指向 map 中第一个元素(按键值排序)的迭代器。end()
返回指向 map 结束点的迭代器,不指向任何元素。rbegin()
和 rend()
分别返回逆向迭代器,指向 map 中最后一个元素(按键值排序)和逆向迭代器的结束点。// 输出 map 中的第一个元素
if (!myMap.empty()) {
std::cout << "First element: " << myMap.begin()->first << ": " << myMap.begin()->second << std::endl;
}
// 输出 map 中的最后一个元素
if (!myMap.empty()) {
std::cout << "Last element: " << myMap.rbegin()->first << ": " << myMap.rbegin()->second << std::endl;
}
emplace_hint
插入元素emplace_hint
函数类似于 emplace
,但在已经知道插入点的情况下,可以提供一个迭代器提示,有可能提高插入效率。
auto hint = myMap.lower_bound("David"); // 获取可能的插入点
myMap.emplace_hint(hint, "Eve", 91); // 在 "David" 之后或相应位置插入新的键值对
extract
移除并返回元素C++17 引入了 extract
函数,可以从容器中移除元素并返回一个包含该元素的 std::pair
,其中 .first
是指向元素的迭代器,.second
是一个包含了原容器中元素的 std::optional
。
if (auto result = myMap.extract("Alice"); result.second) {
std::cout << "Removed Alice with grade: " << result.first->second << std::endl;
// 可以将移除的元素插入到另一个 map 中
anotherMap.insert(std::move(result.first));
}
通过熟悉这些高级用法和功能,开发者可以更加灵活高效地使用 C++ 的 std::map
容器。
merge
合并两个 mapC++17 中引入了 merge
函数,可以将一个 map 的内容合并到另一个 map 中,合并过程中如果遇到相同键值,后者会替换前者。
std::map<std::string, int> map1 = {{"Alice", 85}, {"Bob", 90}};
std::map<std::string, int> map2 = {{"Bob", 92}, {"Charlie", 95}};
map1.merge(map2); // 合并后,map1 中 Bob 的成绩变为 92
// map1: {"Alice": 85, "Bob": 92, "Charlie": 95}
// map2: {}
extract
和 insert
实现元素移动extract
函数可以配合 insert
函数实现元素在 map 间的移动,而不仅仅是复制。
std::map<std::string, int> map1, map2;
// ... 填充 map1 和 map2 ...
// 将 map1 中的 "Alice" 移动到 map2
if (auto it = map1.extract("Alice"); it.second) {
map2.insert(std::move(it.mapped()));
}
// 此时 map1 不再包含 "Alice"
swap
函数交换两个 map 的内容swap
函数可以交换两个 map 的所有内容,包括内部的键值对及其顺序。
std::map<std::string, int> map1 = {{"Alice", 85}, {"Bob", 90}};
std::map<std::string, int> map2 = {{"Charlie", 95}, {"David", 98}};
std::swap(map1, map2);
// 交换后,map1 和 map2 的内容互换
通过学习和实践以上 std::map
的各种用法,开发者能够更好地应对不同场景下的键值对存储和查询需求,编写出高效且易于维护的代码。
当然,以下是更多的 std::map
使用示例:
lower_bound
和 upper_bound
实现范围查找这两个函数可以用来找到 map 中第一个大于等于(小于)指定键的元素,适用于查找某一键值范围内的所有元素。
std::map<std::string, int> grades = {{"Alice", 85}, {"Bob", 90}, {"Charlie", 95}, {"David", 98}};
auto lower = grades.lower_bound("Bob");
auto upper = grades.upper_bound("David");
for (auto it = lower; it != upper; ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
// 输出:Bob: 90 Charlie: 95
emplace_hint
并结合 find
获取更好的插入性能当已知要插入的位置附近时,可以先用 find
查找,然后将返回的迭代器作为 emplace_hint
的参数。
std::map<std::string, int> grades;
auto it = grades.find("Bob");
grades.emplace_hint(it, "Alice", 85); // 如果 "Bob" 已经在 map 中,那么 "Alice" 将插入在其之前
key_comp
和 value_comp
比较器key_comp
返回一个可以用来比较键的仿函数,value_comp
返回一个可以用来比较元素(键值对)的仿函数。
std::map<std::string, int> grades;
// 检查两个键是否按 map 的排序规则相等
if (grades.key_comp()("Alice", "Bob") == 0) {
// ...
}
// 检查两个键值对是否按 map 的排序规则相等
if (grades.value_comp()(std::make_pair("Alice", 85), std::make_pair("Bob", 90)) == 0) {
// ...
}
equal_range
进行精确查找equal_range
返回一个迭代器对,表示 map 中所有键等于给定键的元素范围,对于 map,这始终只包含一个元素。
auto range = grades.equal_range("Alice");
assert(range.first == range.second); // 如果 "Alice" 不存在于 map 中,两者相等
max_size
查询最大容量max_size
函数返回 map 可能容纳的最大元素数量,但实际可用空间可能受系统限制影响。
std::size_t maxSize = grades.max_size();
std::cout << "Max possible size of grades map: " << maxSize << std::endl;
reserve
预留空间虽然 map 不能像 vector 那样直接预留空间,但它会根据需要动态调整内部数据结构,以适应增加的元素。
extract
与 emplace
实现原子化的更新操作可以提取元素、修改其值,然后重新插入,确保在多线程环境下的原子性。
if (auto entry = grades.extract("Bob"); entry.second) {
entry.mapped() = 92; // 修改值
grades.emplace_hint(entry.position(), std::move(entry)); // 重新插入
}
extract
移除元素并转换为普通对象extract
函数可以将 map 中的元素提取出来,并转换为一个普通的键值对(std::pair
)。
if (auto entry = grades.extract("Bob"); entry.second) {
std::pair<const std::string, int> extractedPair = *entry;
// 使用 extractedPair 进行进一步操作
}
extract
清空 map可以通过连续调用 extract
并忽略返回值来清空 map。
while (!grades.empty()) {
grades.extract(grades.begin());
}
std::transform
迭代 map 并应用函数结合迭代器和 std::transform
函数,可以对 map 中的所有值执行某种计算。
std::map<std::string, int> gradesCopy;
std::transform(grades.begin(), grades.end(),
std::inserter(gradesCopy, gradesCopy.end()),
[](const auto& pair) {
return std::make_pair(pair.first, pair.second * 2); // 示例:将成绩加倍
});
以上示例展现了 std::map
更多的特性和用法,帮助开发者深入了解并有效地使用这一容器。
std::copy
将 map 转换为 vector可以将 map 的键或值复制到 vector 中。
std::vector<std::string> keys;
std::copy(grades.begin(), grades.end(),
std::back_inserter(keys),
[](const auto& pair) { return pair.first; });
std::vector<int> values;
std::transform(grades.begin(), grades.end(),
std::back_inserter(values),
[](const auto& pair) { return pair.second; });
std::all_of
, std::any_of
, std::none_of
对 map 进行条件检查bool allAbove90 = std::all_of(grades.begin(), grades.end(),
[](const auto& pair) { return pair.second > 90; });
bool anyBelow80 = std::any_of(grades.begin(), grades.end(),
[](const auto& pair) { return pair.second < 80; });
bool noneEqual95 = std::none_of(grades.begin(), grades.end(),
[](const auto& pair) { return pair.second == 95; });
std::accumulate
计算 map 中所有值的总和int totalScore = std::accumulate(grades.begin(), grades.end(), 0,
[](int sum, const auto& pair) { return sum + pair.second; });
std::for_each
对 map 进行遍历并打印std::for_each(grades.begin(), grades.end(),
[](const auto& pair) { std::cout << pair.first << ": " << pair.second << std::endl; });
std::map::extract
结合 std::set
移除特定键集合中的元素std::set<std::string> studentsToRemove = {"Alice", "Bob"};
for (const auto& student : studentsToRemove) {
if (auto it = grades.extract(student); it.second) {
// 已成功移除学生
}
}
std::map::emplace_hint
更新已存在的键值对auto it = grades.find("Charlie");
if (it != grades.end()) {
grades.emplace_hint(it, "Charlie", it->second + 1); // 假设将成绩增加1分
}
std::unordered_map
改善查找性能(散列映射)在某些场景下,如果你不需要键有序且查找速度更为关键,可以考虑使用 std::unordered_map
。
std::unordered_map<std::string, int> unorderedGrades;
// ... 插入和访问方式类似 ...
std::map::key_type
和 mapped_type
获取键和值的类型using StudentName = std::map<std::string, int>::key_type;
using Grade = std::map<std::string, int>::mapped_type;
std::advance
移动迭代器auto it = grades.begin();
std::advance(it, 2); // 移动到第三个元素的位置
std::prev
和 std::next
访问相邻元素auto it = std::next(grades.begin()); // 第二个元素
auto previous = std::prev(it); // 第一个元素
auto next = std::next(it); // 第三个元素
请注意,在实际项目中,应结合具体情况合理使用这些技术,以达到代码简洁、高效的目的。
python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)
50个开发必备的Python经典脚本(11-20)
50个开发必备的Python经典脚本(21-30)
50个开发必备的Python经典脚本(31-40)
50个开发必备的Python经典脚本(41-50)
————————————————
最后我们放松一下眼睛