multimap是C++中唯一原生支持重复键的有序关联容器,基于红黑树实现,允许insert相同key的多个值,禁用operator[],需用equal_range遍历匹配key的所有元素,erase(key)可一次性删除全部同key节点。

multimap 是 C++ 标准库中唯一原生支持重复键的有序关联容器,它不强制键唯一,但要求键值对按 key 严格弱序排列(默认升序),底层通常基于红黑树实现。
如何声明和插入重复键的元素
与 map 不同,multimap 允许调用 insert() 多次插入相同 key 的不同值,且不会覆盖或报错。注意不能用 operator[] —— 它在 multimap 中被禁用,因为下标访问语义与“多值”冲突。
- 必须使用
insert():支持std::pair、std::make_pair或花括号初始化 - 推荐用
emplace()避免临时对象拷贝(C++11 起) - 插入后容器自动按
key排序,相同key的多个值按插入顺序(稳定排序)相邻存放
std::multimapmm; mm.insert({1, "apple"}); mm.insert(std::make_pair(1, "banana")); // 同 key,合法 mm.emplace(2, "cherry"); // 更高效
如何遍历所有匹配 key 的元素
不能用 find() 直接取单个值——它只返回第一个匹配项的迭代器。要获取全部,必须用 equal_range(),它返回一个 std::pair,表示 [first, last) 区间内所有 key 相等的元素。
-
equal_range(key)是最安全、最高效的批量查找方式 - 若 key 不存在,返回的两个迭代器相等,循环体不执行
- 不要混用
lower_bound()+upper_bound()手动计算范围,易出错且可读性差
auto range = mm.equal_range(1);
for (auto it = range.first; it != range.second; ++it) {
std::cout << it->first << ": " << it->second << "\n";
}
删除指定 key 的所有元素时要注意什么
erase(key) 会直接删除该 key 对应的所有节点,返回删除个数(size_t),这是最简洁的方式。但需警惕:若误用 erase(iterator) 只删一个,可能遗漏其余重复项。
立即学习“C++免费学习笔记(深入)”;
- 用
mm.erase(1)删除所有key == 1的元素,一步到位 - 若只想删其中一个,先用
find()获取单个迭代器再erase(it) - 删除操作后,其他迭代器是否失效?—— 是的,被删节点的迭代器立即失效;未被删的仍有效(红黑树局部调整)
multimap 和 unordered_multimap 的关键区别
当性能成为瓶颈且不需要有序遍历时,应考虑 unordered_multimap:它用哈希表实现,平均 O(1) 插入/查找,但不保证任何顺序,且要求 key 类型提供 std::hash 和 operator==。
-
multimap:有序、稳定、支持lower_bound/upper_bound等范围操作 -
unordered_multimap:无序、更快、但无法做“小于某 key 的所有元素”这类查询 - 二者接口高度一致,替换成本低,但语义差异影响算法设计
真正容易被忽略的是:multimap 的“重复键”能力不是为替代数组而设的,它是为建模一对多关系(如学号→多门课程成绩)或需要按 key 分组检索的场景服务的。滥用会导致迭代开销陡增,尤其当某个 key 对应成百上千个 value 时,equal_range 返回的区间遍历本身就成了性能热点。











