
在 C++ 标准库中,map 是一种高效的关联容器,基于红黑树(Red-Black Tree)实现。它能够将键值对(Key-Value)按照特定顺序存储,支持快速查找、插入和删除操作。本文将从底层原理到高级应用,全面解析 map 的核心特性。
map是C++ STL中的一种关联容器,用于存储键值对。每个键(key)必须是唯一的,而值(value)可以重复。map中的元素会根据键自动排序,默认按键的升序排列。其底层实现通常基于红黑树(一种自平衡二叉搜索树),保证了高效的操作性能。
map不允许容器中有重复的键,而multimap允许容器中有重复的键。multimap的查找操作可能会返回一个迭代器范围,表示所有匹配键的值集合。C++ STL容器分为序列容器和关联容器两大类。map作为关联容器的核心类型,提供基于键值对的快速查找能力,与unordered_map形成有序/无序的互补结构。
// STL容器分类简图
/*
关联容器
├─ 有序关联容器
│ ├─ map
│ ├─ set
│ ├─ multimap
│ └─ multiset
└─ 无序关联容器
├─ unordered_map
└─ unordered_set
*/map的标准声明格式:
template<
class Key,
class T,
class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>
> class map;Key:不可变键类型,需满足严格弱序T:映射值类型
Compare:比较函数对象(默认std::less)
Allocator:内存分配器
pair提供多种构造方式,灵活适配不同场景:
①默认构造
std::pair<int, std::string> p1; // first=0, second=""②值初始化构造
std::pair<double, char> p2(3.14, 'A');③拷贝构造
std::pair<const char*, size_t> p3("hello", 5);
std::pair<const char*, size_t> p4(p3); // 深拷贝④模板推导构造(C++11起)
auto p5 = std::make_pair(42, "answer"); // 自动推导类型为pair<int, const char*>map容器非常适合实现字典功能,其中键为单词,值为单词的解释。
map容器来存储配置项及其对应的值。
map容器来存储缓存数据,并根据键快速查找和更新缓存。
map容器可以方便地用于数据的排序和统计,例如统计单词出现的频率。
map容器提供了丰富的成员函数,用于操作容器中的元素。以下是一些常用的成员函数。
map容器。
std::map<int, std::string> myMap;map容器的内容初始化当前容器。 std::map<int, std::string> myMap1 = {{1, "one"}, {2, "two"}};
std::map<int, std::string> myMap2(myMap1); // 拷贝构造map容器的内容赋值给另一个容器。std::map<int, std::string> myMap1 = {{1, "one"}, {2, "two"}};
std::map<int, std::string> myMap2;
myMap2 = myMap1; // 赋值操作std::map<int, std::string> myMap;
myMap.insert(std::pair<int, std::string>(1, "one"));
myMap.insert(std::make_pair(2, "two"));std::map<int, std::string> myMap;
myMap.emplace(3, "three"); // 直接构造键值对并插入std::map<int, std::string> myMap;
myMap[4] = "four"; // 插入或更新键值对std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}, {3, "three"}};
myMap.erase(myMap.begin()); // 删除第一个元素
myMap.erase(2); // 删除键为2的元素
myMap.erase(myMap.begin(), myMap.end()); // 清空容器std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}};
myMap.clear(); // 清空容器std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}};
auto it = myMap.find(1);
if (it != myMap.end()) {
std::cout << "Found: " << it->second << std::endl;
} else {
std::cout << "Not found." << std::endl;
}map,结果要么是0,要么是1)。
std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}};
int count = myMap.count(1);
std::cout << "Count of key 1: " << count << std::endl;std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}};
std::cout << "Size of the map: " << myMap.size() << std::endl;std::map<int, std::string> myMap;
if (myMap.empty()) {
std::cout << "The map is empty." << std::endl;
} else {
std::cout << "The map is not empty." << std::endl;
}map容器的内容。
std::map<int, std::string> myMap1 = {{1, "one"}, {2, "two"}};
std::map<int, std::string> myMap2 = {{3, "three"}, {4, "four"}};
myMap1.swap(myMap2); // 交换两个容器的内空①时间复杂度
map基于红黑树实现,这些操作的时间复杂度均为O(log n),其中n为容器中的元素数量。map容器的时间复杂度为O(n),因为需要访问每个元素。②内存占用
map容器的内存占用通常比unordered_map(基于哈希表实现)更紧凑,因为红黑树不需要额外的存储空间来处理碰撞冲突。③线程安全性
map容器不是线程安全的,在多线程环境下使用时需要采取额外的同步措施,如使用互斥锁来保护对容器的访问。map 采用红黑树作为底层数据结构,这是一种平衡二叉搜索树(Balanced BST)。红黑树的每个节点都有一个颜色属性(红或黑),通过颜色翻转和旋转操作保持树的平衡。其核心特性包括:
#include <map>
#include <string>
// 基本定义
std::map<int, std::string> scores;
// 初始化方式
std::map<int, std::string> studentScores = {
{1001, "Alice"},
{1002, "Bob"}
};方式一:insert 方法
// 插入键值对
scores.insert(std::pair<int, std::string>(1003, "Charlie"));
// 插入初始化列表
scores.insert({1004, "David"});方式二:operator[]
// 若键不存在则插入默认值
scores[1005] = "Eve";// 通过键访问值
std::cout << scores[1001] << std::endl; // 输出:Alice
// 安全访问(检查键是否存在)
auto it = scores.find(1006);
if (it != scores.end()) {
std::cout << "Found: " << it->second << std::endl;
} else {
std::cout << "Key not found" << std::endl;
}// 删除指定键
scores.erase(1002);
// 删除迭代器指向的元素
auto eraseIt = scores.find(1003);
if (eraseIt != scores.end()) {
scores.erase(eraseIt);
}// 正向遍历
for (const auto& entry : scores) {
std::cout << entry.first << ": " << entry.second << std::endl;
}
// 逆向遍历
for (auto it = scores.rbegin(); it != scores.rend(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}类型 | 描述 |
|---|---|
iterator | 普通迭代器(可读可写) |
const_iterator | 常量迭代器(只读) |
reverse_iterator | 反向迭代器 |
示例:使用结构体作为键
struct Student {
int id;
std::string name;
bool operator<(const Student& other) const {
return id < other.id;
}
};
std::map<Student, double> studentGrades;
// 插入数据
studentGrades[{1001, "Alice"}] = 95.5;场景:降序排序
struct CompareDesc {
bool operator()(int a, int b) const {
return a > b;
}
};
std::map<int, std::string, CompareDesc> reverseMap;
reverseMap.insert({1, "A"});
reverseMap.insert({2, "B"});
// 输出顺序:2 -> B,1 -> A预分配内存
// 预先分配足够空间
scores.reserve(1000);批量插入
std::vector<std::pair<int, std::string>> data = {
{1001, "A"}, {1002, "B"}
};
scores.insert(data.begin(), data.end());特性 | map | unordered_map |
|---|---|---|
底层结构 | 红黑树 | 哈希表 |
有序性 | 按键有序 | 无序 |
查找时间 | O(log n) | O (1)(平均情况) |
插入 / 删除时间 | O(log n) | O (1)(平均情况) |
// 若键不存在,会插入默认构造的值
int value = scores[1006]; // 可能意外插入键 1006确保比较函数满足:
map,追求速度时用 unordered_mapinsert 而非 operator[] 进行插入操作insert 的返回值检查map容器是C++ STL中一种非常重要的关联容器,它以键值对的形式存储数据,并根据键自动排序。map提供了丰富的成员函数,支持高效的插入、删除和查找操作。在实际应用中,map可以用于字典实现、配置文件解析、缓存机制等多种场景。
#include <iostream>
#include <map>
#include <string>
// 自定义降序比较函数结构体
struct DescCompare {
// 重载函数调用运算符,实现降序比较
bool operator()(int a, int b) const {
return a > b;
}
};
int main() {
// 初始化一个存储学生信息的 map,键为学生 ID,值为学生姓名
std::map<int, std::string> students = {
{1001, "Alice"},
{1002, "Bob"}
};
// 插入新的学生信息
// 使用 insert 函数插入键值对
students.insert({1003, "Charlie"});
// 使用 [] 运算符插入键值对
students[1004] = "David";
// 遍历输出所有学生信息
std::cout << "All students:" << std::endl;
// 使用迭代器遍历 map
for (auto it = students.begin(); it != students.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
// 查找指定 ID 的学生信息
auto findIt = students.find(1002);
if (findIt != students.end()) {
std::cout << "Found: " << findIt->second << std::endl;
}
// 删除指定 ID 的学生信息
students.erase(1001);
// 创建一个使用自定义降序比较函数的 map
std::map<int, std::string, DescCompare> reversedMap;
// 插入元素到降序 map 中
reversedMap.insert({5, "E"});
reversedMap.insert({3, "C"});
// 遍历输出降序 map 中的元素
std::cout << "\nReversed order:" << std::endl;
for (auto it = reversedMap.begin(); it != reversedMap.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
return 0;
}
using声明在模板编程中有着重要应用,如定义模板类型别名等。