C++——STL之map容器
简介:
简单来说,std::map(C++)或者类似的 Map 结构(如 Python 中的 dict、Java 中的 HashMap),就像是一个特殊的字典。它不像数组那样用 0, 1, 2... 的数字作为下标,而是允许你用任意类型的数据作为索引来找到对应的数据。
这个“索引”就是键,找到的“数据”就是值。
为什么使用map容器?
如果你的数据只是单纯的一排数字,用 vector 或数组就够了。但如果你需要通过某个特征(比如人名、ID号、配置项的名称)来快速存取数据,map 就是最佳选择。
语义清晰:代码里写 score["Alice"] 比“遍历数组找 Alice”要直观得多,更符合人类思维。
查找极快:在海量数据下,map 的查找效率远高于数组。
1. 键值对
这是 Map 存储数据的基本单位。每一个元素都包含两部分:
Key(键):唯一的,用来查找。比如“学号”、“人名”。
Value(值):实际存储的数据。比如“成绩”、“电话号码”。
比如你要存储一个通讯录:
键: “张三” (string)
值: “13800138000” (string)
2. std::map 的核心特性
在 C++ 标准库中,map 的底层通常是红黑树实现的,这决定了它的性格:
自动排序:它内部总是按照 Key 的大小顺序排好的(默认从小到大)。你插入 {"banana", 2} 和 {"apple", 1},遍历时它会先给你 apple。这和 unordered_map(哈希表,无序)不一样。
Key 必须唯一:你不能插入两个 Key 相同的元素。如果强行插入已存在的 Key,旧的值会被覆盖。
查找速度快:虽然是树结构,但查找速度依然很快(O(log n)),比遍历数组快得多。
【在 C++ 的 std::map 中,遍历输出顺序绝对不是按照你插入的顺序来的,而是按照键的大小排序的。
map容器实现的底层原理:
底层结构:std::map 的底层通常是一棵红黑树(一种自平衡二叉搜索树)。
树的逻辑:二叉树的特点就是“左小右大”。当你插入数据时,map 会自动根据 Key 的大小,把数据放到树的正确位置上。
遍历逻辑:当你使用迭代器(begin() 到 end())遍历时,map 其实是在做“中序遍历”(左子树 -> 根节点 -> 右子树),这正好就是把数据从小到大排好序的顺序。】
【key大小的计算:
1. 基本数据类型(int, float, double)
最直观,直接比数值大小。
2. 字符串类型 (std::string)
这是最常用但也容易误解的地方。字符串比较大小是按字典序(Lexicographical),也就是像查英语词典那样,一个字符一个字符地比。
比较规则:
从左到右,比较对应位置字符的 ASCII 码值。谁先出现不同的字符,谁就小(ASCII 码小的在前面)。如果前面都一样,短的字符串小。
3. 字符指针 (const char*)
这是一个大坑!如果你用的是 const char*(C风格的字符串)作为 Key:它比较的不是字符串的内容,而是指针的内存地址!
因为 char* 只是个指针,默认的 < 只比较两个指针存放在哪里的地址值,不看它们指向的 “Hello” 或 “World” 内容。
所以作为 Key 尽量不要用 const char*,一定要用 std::string,否则排序结果会让你摸不着头脑。
4. 自定义类型(结构体/类)
如果你用自己定义的结构体做 Key(比如 struct Person),编译器会直接报错,因为它不知道什么叫“张三小于李四”。
你需要告诉它怎么比。有两种方法:
方法 A:重载 < 运算符
方法 B:自定义比较器【在定义 map 的时候传入一个自定义的规则函数。】
3、示例代码
示例
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
// 1. 定义一个 map:键是 string(名字),值是 int(分数)
map<string, int> scores;
// 2. 插入数据(构造键值对)
// 方法一:直接用下标运算符 [ ],最直观
scores["Alice"] = 95;
scores["Bob"] = 88;
// 方法二:使用 insert 和 pair
scores.insert(make_pair("Charlie", 92));
// 3. 访问和修改
// 如果 Key 存在,修改它的 Value
scores["Bob"] = 90;
// 4. 遍历(注意:输出顺序是按名字字母排序的)
// it 是一个迭代器,指向一个键值对 (pair)
// it->first 是 Key,it->second 是 Value
for (map<string, int>::iterator it = scores.begin(); it != scores.end(); ++it) {
cout << it->first << ": " << it->second << endl;
}
// 输出:
// Alice: 95
// Bob: 90
// Charlie: 92
// 5. 查找
map<string, int>::iterator findIt = scores.find("Alice");
if (findIt != scores.end()) {
cout << "Found Alice's score: " << findIt->second << endl;
}
return 0;
}
更多推荐

所有评论(0)