在C++标准模板库中,std::multimap是一种关联式容器,它允许同一个键对应多个不同的元素,和std::map的核心区别在于键的唯一性限制被放开,同时所有元素会按照键的大小自动排序,底层通过红黑树实现,插入、查找、删除操作的时间复杂度都是对数级别。

std::multimap的基本定义与初始化
要使用std::multimap,首先需要包含头文件<map>,它的模板参数有两个,第一个是键的类型,第二个是对应值的类型,也可以额外指定排序规则,默认按照键的升序排列。
以下是几种常见的定义和初始化方式:
#include <map>
#include <string>
#include <iostream>
int main() {
// 1. 定义空的std::multimap,键为int类型,值为string类型
std::multimap<int, std::string> mmap1;
// 2. 通过初始化列表初始化,允许重复键
std::multimap<int, std::string> mmap2 = {
{1, "apple"},
{1, "banana"}, // 键1重复
{2, "cherry"},
{1, "date"} // 键1再次重复
};
// 3. 自定义排序规则,按照键的降序排列
std::multimap<int, std::string, std::greater<int>> mmap3;
return 0;
}
元素插入操作
std::multimap插入元素的方式和std::map类似,但是不需要判断键是否已经存在,因为允许重复键,所以每次插入都会新增元素。常用的插入方法有insert成员函数和emplace成员函数。
#include <map>
#include <string>
#include <iostream>
int main() {
std::multimap<int, std::string> mmap;
// 使用insert插入键值对,参数为pair对象
mmap.insert(std::pair<int, std::string>(1, "first"));
// 也可以使用make_pair简化写法
mmap.insert(std::make_pair(1, "second"));
// 直接传递两个参数构造pair
mmap.insert({2, "third"});
// 使用emplace直接构造元素,效率更高
mmap.emplace(2, "fourth");
mmap.emplace(1, "fifth");
// 输出所有元素验证插入结果
for (auto &item : mmap) {
std::cout << item.first << " : " << item.second << std::endl;
}
// 输出结果会按键升序排列,键1对应三个值,键2对应两个值
return 0;
}
查找指定键的所有元素
由于std::multimap允许重复键,所以无法通过find函数获取某个键对应的所有元素,find只会返回第一个匹配键的迭代器。要获取某个键对应的所有值,需要使用lower_bound和upper_bound函数,或者equal_range函数。
使用lower_bound和upper_bound
lower_bound(key)返回第一个键大于等于key的迭代器,upper_bound(key)返回第一个键大于key的迭代器,两者的区间就是所有键等于key的元素范围。
#include <map>
#include <string>
#include <iostream>
int main() {
std::multimap<int, std::string> mmap = {
{1, "a"}, {1, "b"}, {2, "c"}, {1, "d"}, {3, "e"}
};
int target_key = 1;
auto it_low = mmap.lower_bound(target_key);
auto it_up = mmap.upper_bound(target_key);
std::cout << "键" << target_key << "对应的所有值:" << std::endl;
for (auto it = it_low; it != it_up; ++it) {
std::cout << it->second << std::endl;
}
// 输出结果:a b d
return 0;
}
使用equal_range
equal_range(key)会直接返回一个pair,first是lower_bound的结果,second是upper_bound的结果,使用起来更简洁。
#include <map>
#include <string>
#include <iostream>
int main() {
std::multimap<int, std::string> mmap = {
{1, "a"}, {1, "b"}, {2, "c"}, {1, "d"}, {3, "e"}
};
int target_key = 2;
auto range = mmap.equal_range(target_key);
std::cout << "键" << target_key << "对应的所有值:" << std::endl;
for (auto it = range.first; it != range.second; ++it) {
std::cout << it->second << std::endl;
}
// 输出结果:c
return 0;
}
遍历容器元素
std::multimap的遍历方式和普通容器一致,可以使用迭代器遍历、范围for循环遍历,也可以使用for_each算法遍历。
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
int main() {
std::multimap<int, std::string> mmap = {
{1, "x"}, {2, "y"}, {1, "z"}
};
// 1. 迭代器遍历
std::cout << "迭代器遍历结果:" << std::endl;
for (auto it = mmap.begin(); it != mmap.end(); ++it) {
std::cout << it->first << " : " << it->second << std::endl;
}
// 2. 范围for循环遍历
std::cout << "范围for遍历结果:" << std::endl;
for (auto &item : mmap) {
std::cout << item.first << " : " << item.second << std::endl;
}
// 3. for_each算法遍历
std::cout << "for_each遍历结果:" << std::endl;
std::for_each(mmap.begin(), mmap.end(), [](const auto &item) {
std::cout << item.first << " : " << item.second << std::endl;
});
return 0;
}
删除元素操作
std::multimap提供了多种删除元素的方式,包括通过迭代器删除单个元素、通过键删除所有对应元素、通过迭代器区间删除元素。
#include <map>
#include <string>
#include <iostream>
int main() {
std::multimap<int, std::string> mmap = {
{1, "a"}, {1, "b"}, {2, "c"}, {1, "d"}, {3, "e"}
};
// 1. 删除第一个键为1的元素(通过find获取第一个迭代器)
auto it = mmap.find(1);
if (it != mmap.end()) {
mmap.erase(it);
}
// 2. 删除所有键为1的元素,返回删除的元素个数
size_t del_count = mmap.erase(1);
std::cout << "删除了" << del_count << "个键为1的元素" << std::endl;
// 3. 删除迭代器区间内的元素,这里删除所有剩余元素
mmap.erase(mmap.begin(), mmap.end());
std::cout << "删除后容器大小:" << mmap.size() << std::endl;
return 0;
}
std::multimap与std::map的核心差异
两者都是标准库的关联容器,底层都是红黑树实现,主要差异如下:
| 对比项 | std::map | std::multimap |
|---|---|---|
| 键唯一性 | 键唯一,不允许重复 | 键可以重复,允许同一个键对应多个值 |
| operator[]支持 | 支持,可通过键直接访问或修改值 | 不支持,因为无法确定唯一对应的值 |
| insert返回值 | 返回pair,包含迭代器和是否插入成功的bool值 | 只返回插入元素的迭代器 |
| 适用场景 | 键值一一对应的场景 | 一个键对应多个值的场景,比如学生ID对应多门课程成绩 |
实际开发注意事项
- std::multimap不允许使用
operator[]访问元素,因为存在重复键,无法确定返回哪一个值,访问元素需要通过迭代器或者find系列函数。 - 插入元素时不会因为键重复而覆盖原有元素,所有重复键的元素都会被保留,按插入顺序在键的区间内排列。
- 如果需要无序存储、允许重复键的映射,可以考虑使用std::unordered_multimap,底层基于哈希表实现,平均查找时间复杂度是O(1),但是元素不会自动排序。
- 遍历的时候如果修改元素的值不会影响排序,但是如果修改元素的键会破坏容器的内部结构,导致未定义行为,所以不要直接修改迭代器指向的键。
总结来说,当遇到需要存储键值对且允许键重复的场景时,std::multimap是非常合适的选择,掌握它的插入、查找、遍历、删除操作,就能应对大部分相关的开发需求。
std::multimapC++multimap用法重复键映射修改时间:2026-06-29 08:03:49