c++数据结构10——map结构详解
一、引言:为什么需要map?
考虑这样一个问题:在一段文本中统计每个单词出现的次数,并找出出现次数最多的单词。例如输入:
red apple ,red apple,i love red
期望输出:red 3
传统数组无法解决这个问题,因为:
-
数组索引只能是整数,不能是字符串
-
文本中的单词数量不确定
-
需要动态存储键值对
map容器正是为解决这类问题而设计的关联容器,它提供了高效的键值对存储和检索能力。
二、map基本概念
1.核心特点
-
键值对存储:每个元素包含一个键(key)和一个值(value)
-
自动排序:元素根据key自动升序排列
-
唯一键:每个key在map中唯一
-
高效操作:查找、插入、删除时间复杂度为O(log n)
2.底层实现
map基于红黑树(自平衡二叉查找树)实现,这使得它能够:
-
保持元素有序
-
提供高效的查找操作
-
动态调整树结构保持平衡
三、map的定义与基本操作
1.头文件与定义
#include <map> // 必须包含的头文件// 定义map的基本语法 map<key类型, value类型> 映射名称;// 示例:字符串到整数的映射 map<string, int> wordCount;
2.三种插入元素方式
-
下标操作符[]
wordCount["apple"] = 3; // 插入键"apple",值3
2.insert()函数
wordCount.insert(make_pair("banana", 5)); // 使用make_pair创建键值对
3.value_type
wordCount.insert(map<string, int>::value_type("orange", 2));
注意:使用insert插入已存在的键不会覆盖原值,而使用[]会覆盖原值
3.访问与遍历map元素
1. 下标访问
cout << wordCount["apple"]; // 输出3
注意 :使用不存在的键访问会自动创建该键,值为0
2. 迭代器遍历
for(map<string, int>::iterator it = wordCount.begin(); it != wordCount.end(); it++) {cout << it->first << ": " << it->second << endl; // first是键,second是值 }
3. C++11范围for循环
for(auto& pair : wordCount) {cout << pair.first << ": " << pair.second << endl; }
四、常用成员函数
函数 | 功能 | 示例 | 时间复杂度 |
---|---|---|---|
find(key) | 查找指定键 | auto it = m.find("apple"); | O(log n) |
count(key) | 统计键出现次数 | if(m.count("apple") > 0) {...} | O(log n) |
size() | 返回元素数量 | int num = m.size(); | O(1) |
empty() | 判断是否为空 | if(m.empty()) {...} | O(1) |
erase(key) | 删除指定键 | m.erase("apple"); | O(log n) |
clear() | 清空map | m.clear(); | O(n) |
五、应用实例:统计单词频率
问题描述
输入一段文本,统计每个单词的出现频率,输出出现次数最多的单词及其次数
输入样例
Can a can can a can? It can!
输出结果
can 5
解题思路
-
分割文本为单词
-
统一转换为小写
-
使用map统计每个单词出现次数
-
遍历map找到最大频率的单词
完整代码
#include <iostream> #include <map> #include <cctype> // 用于tolower() using namespace std;// 处理单词:转换为小写并移除非字母字符 string processWord(string word) {string result = "";for(char c : word) {if(isalpha(c)) { // 只保留字母result += tolower(c); // 转换为小写}}return result; }int main() {map<string, int> wordCount;string word;while(cin >> word) { // 逐个读取单词string processed = processWord(word);if(!processed.empty()) { // 忽略空单词wordCount[processed]++; // 计数增加}}// 找出出现次数最多的单词string mostFrequent;int maxCount = 0;for(auto& pair : wordCount) {if(pair.second > maxCount || (pair.second == maxCount && pair.first < mostFrequent)) {mostFrequent = pair.first;maxCount = pair.second;}}cout << mostFrequent << " " << maxCount << endl;return 0; }
六、map的性能特点与最佳实践
性能特点
-
优点:
-
自动排序
-
键唯一性保证
-
高效的查找操作(O(log n))
-
-
缺点:
-
内存占用较大(每个节点需要额外指针)
-
插入/删除可能引起树结构调整
-