C++ multimap用法详解_C++允许重复key的映射容器操作

multimap是C++ STL中允许键重复的关联容器,基于红黑树实现,元素按键有序存储,支持O(log n)的插入、删除与查找。1. 特性:支持重复键、自动排序、不可用下标访问。2. 操作:通过insert或emplace插入;find、count和equal_range处理查找;erase删除元素;迭代器遍历。3. 可自定义比较规则如降序。4. 适用一对多场景,如成绩映射学生、事件绑定多个回调。

在C++标准库中,multimap 是一种关联式容器,属于 STL 的一部分。它与 map 非常相似,但关键区别在于:multimap 允许键(key)重复,也就是说多个元素可以拥有相同的键。这使得 multimap 在处理一对多映射关系时非常有用。

1. multimap 基本特性

multimap 内部通常基于红黑树实现,元素按照键自动排序(默认升序),每个元素是一个键值对(key-value pair),类型为 std::pair

主要特点包括:

  • 支持重复的 key
  • 按键有序存储(可自定义比较函数)
  • 插入、删除、查找的时间复杂度为 O(log n)
  • 不支持通过下标直接访问(因为 key 不唯一)

2. 常用操作和成员函数

以下是 multimap 中常用的操作方法:

构造与赋值
  • multimap mmp;:创建一个空的 multimap
  • multimap mmp = {{1, "apple"}, {1, "banana"}, {2, "cherry"}};:初始化包含重复 key 的元素
  • mmp = another_mmp;:赋值操作
插入元素

由于不能使用下标访问,插入必须通过 insert()emplace()

  • mmp.insert({key, value});
  • mmp.insert(std::make_pair(key, value));
  • mmp.emplace(key, value);:原地构造,效率更高

示例:

multimap mmp;
mmp.insert({1, "one"});
mmp.insert({1, "uno"});  // 允许重复 key
mmp.emplace(2, "two");
查找元素

由于 key 可能对应多个值,不能像 map 一样用 operator[] 获取。应使用以下方法:

  • find(key):返回指向第一个匹配 key 的迭代器,未找到返回 end()
  • count(key):返回指定 key 的元素个数
  • equal_range(key):返回一个 std::pair,表示所有相同 key 的范围

遍历某个 key 的所有值:

auto range = mmp.equal_range(1);
for (auto it = range.first; it != range.second; ++it) {
    cout << it->second << endl;  // 输出 "one", "uno"
}
删除元素
  • erase(key):删除所有等于 key 的元素,返回删除个数
  • erase(iterator):删除指定位置的元素
  • erase(first, last):删除一个区间内的元素
  • 示例:

    mmp.erase(1);  // 删除所有 key 为 1 的元素
    
    遍历 multimap

    使用迭代器遍历所有元素(按 key 排序):

    for (const auto& pair : mmp) {
        cout << pair.first << ": " << pair.second << endl;
    }
    

    3. 自定义比较规则

    默认情况下,multimap 按 key 升序排列。可通过自定义比较函数改变排序方式。

    例如,按降序排列:

    multimap> mmp;
    mmp.insert({1, "a"});
    mmp.insert({3, "c"});
    mmp.insert({2, "b"});
    // 输出顺序:3:c, 2:b, 1:a
    

    也可以传入仿函数或 lambda(需用 decltype 和构造参数)。

    4. 应用场景举例

    multimap 适合如下场景:

    • 学生按成绩分类:多个学生可能有相同分数
    • 电话簿中一个人有多个号码(以姓名为 key)
    • 事件系统中,一个事件类型绑定多个回调函数

    示例:按分数存储学生姓名

    multimap students;
    students.emplace(85, "Alice");
    students.emplace(90, "Bob");
    students.emplace(85, "Charlie");
    
    auto range = students.equal_range(85);
    cout << "得分 85 的学生:" << endl;
    for (auto it = range.first; it != range.second; ++it) {
        cout << it->second << endl;
    }
    

    基本上就这些。multimap 提供了灵活的一对多映射能力,合理使用能简化很多数据组织逻辑。注意避免误用 operator[],并善用 equal_range 处理重复键。不复杂但容易忽略细节。