基本用法
- 声明:
std::map<KeyType, ValueType> mapName;
- 其中
KeyType
是键的类型,ValueType
是值的类型。 - 插入元素:使用
insert
成员函数:
mapName.insert(std::make_pair(key, value)); // 或者 mapName[key] = value; // 如果key已经存在,则会更新对应的value
- 访问元素:
- 通过键直接访问:
ValueType &val = mapName[key]; // 返回引用,如果key不存在则插入默认构造的value
- 使用迭代器遍历:
for(auto it = mapName.begin(); it != mapName.end(); ++it) { std::cout << "Key: " << it->first << ", Value: " << it->second << std::endl; } // C++11以后也可以使用范围for循环 for(const auto &entry : mapName) { std::cout << "Key: " << entry.first << ", Value: " << entry.second << std::endl; }
- 删除元素:
- 删除特定键的元素:
mapName.erase(key);
- 删除迭代器指向的元素:
mapName.erase(iterator);
- 删除一个范围内的元素:
mapName.erase(startIterator, endIterator);
- 查找元素:使用
find
成员函数,返回一个迭代器指向该键的元素,如果不存在则返回end()
:
auto it = mapName.find(key); if(it != mapName.end()) { // 找到了,可以使用it->first和it->second } else { // 没找到 }
- 检查元素是否存在:可以直接用
find
结果判断,或者使用count
方法,它返回与给定键匹配的元素个数(通常是0或1):
if(mapName.count(key) > 0) { // 存在 }
注意事项
- 排序:
map
中的元素默认按照键的升序排序。键的类型需要支持比较操作,通常这意味着键类型需要重载<
运算符,或者提供一个自定义的比较函数作为模板参数。 - 唯一性:键在
map
中必须是唯一的。尝试插入已存在的键时,如果使用[]
操作符,实际上会更新对应的值;而使用insert
不会改变已有的键值对。 - 性能:由于底层实现为平衡二叉搜索树(通常是红黑树),所以插入、删除和查找操作的平均时间复杂度为O(log n),其中n是容器中的元素数量。
- 内存管理:
map
中的元素是连续存储的,但键和值不是连续存放的,每个键值对作为一个节点存储。 - 迭代器稳定性:在插入和删除操作中,除了指向被直接操作的元素的迭代器外,其他迭代器保持有效。但是,插入可能导致重新平衡树结构,从而改变迭代器的顺序。
适用情形
- 键值映射: 当你需要根据某个特定的键(key)快速查找、插入或删除与其关联的值(value)时,
map
是理想的选择。例如,在数据库索引、配置文件解析、电话簿应用中,都可以使用map
来实现键值对的存储和查询。 - 排序与索引: 由于
map
内部自动根据键对元素进行排序(默认为升序),它可以用来维护有序的数据集合,如成绩排名、事件时间排序等场景。 - 计数与频率统计: 虽然
std::unordered_map
在某些计数场景下可能更快,但在需要按顺序输出统计结果或进行区间查询时,map
更合适。例如,统计文本中单词出现的频次并按字母顺序输出。 - 唯一性保证: 当需要确保每个键在容器中唯一时,
map
自动拒绝插入重复的键,这在需要唯一标识符的场景中非常有用。 - 区间操作:
map
支持迭代器遍历和范围查找,使得在有序数据上进行区间查找或操作变得容易。 - 最值查找: 利用
map
的有序性,可以快速找到键值对中的最大值或最小值,或者基于某个键范围查找元素。 - 实现特定数据结构: 如堆栈、队列(特别是优先队列,通过自定义比较函数)等,当需要在基础数据结构上增加排序或查找功能时,
map
可作为基础。
总之,map
容器因其自动排序和键值唯一性的特点,非常适合那些需要高效地执行基于键的查找、插入、删除操作,同时还需要保持元素有序的应用场景。通过合理使用 map
,可以高效地处理需要键值对应关系且键唯一的数据结构问题。
题目示例(AI生成)
题目: 统计一篇文章中每个单词出现的次数。
要求: 读入一篇英文文章,输出文章中每个单词及其出现的次数,单词不区分大小写,忽略标点符号。
#include <iostream> #include <map> #include <string> #include <cctype> // 包含字符处理函数,如tolower() using namespace std; // 函数用于清理单词,去除前后空格和转为小写 string cleanWord(string word) { word.erase(0, word.find_first_not_of(" \t\n\r\f\v")); // 移除前导空白 word.erase(word.find_last_not_of(" \t\n\r\f\v") + 1); // 移除尾随空白 transform(word.begin(), word.end(), word.begin(), ::tolower); // 转换为小写 return word; } int main() { map<string, int> wordCount; // 使用map存储单词计数 string word; cout << "请输入文章内容,以换行结束输入:" << endl; while (getline(cin, word)) { // 逐行读取输入 string cleanedWord = cleanWord(word); // 清理并转换单词 if (!cleanedWord.empty()) { // 忽略空行 size_t pos = 0; while ((pos = cleanedWord.find(' ')) != string::npos) { // 分割单词 string singleWord = cleanedWord.substr(0, pos); wordCount[singleWord]++; cleanedWord.erase(0, pos + 1); } wordCount[cleanedWord]++; // 处理最后一词 } } cout << "单词统计结果:" << endl; for (const auto &entry : wordCount) { cout << entry.first << ": " << entry.second << "次" << endl; } return 0; }
- 我们首先定义了一个
cleanWord
函数,用于去除单词的前后空格并将其转换为小写,以便统计时不区分大小写。 - 使用
std::map<string, int>
数据结构来存储每个单词及其出现的次数。 - 通过
getline(cin, word)
逐行读取用户输入的文章。 - 对每一行进行单词分割,将每个单词清理后作为键存入
wordCount
,并递增其对应的值(计数)。 - 最后,遍历
wordCount
,输出每个单词及其出现次数。
此代码展示了 std::map
在处理和统计大量数据时的实用性,尤其是在需要根据特定键(这里是单词)进行计数或分组的场景。