map 系列是 C++ STL 中基于键值对(key-value)的关联容器,核心作用是通过唯一的 key 快速查找、存取对应的 value,是开发中最常用的容器之一。

本文会覆盖 std::mapstd::multimapstd::unordered_mapstd::unordered_multimap 四大核心容器,从底层原理、用法、区别、实战场景全方位讲解。

一、map 系列核心概念

1. 核心定义

  • 存储形式:键值对(pair<key, value>),key 是索引,value 是存储的数据
  • 核心能力:按键查找(而非按位置),时间复杂度远低于数组 /vector
  • 分类标准:
    1. key 是否允许重复(map/multimap)
    2. 底层是否有序(有序 map / 无序 unordered_map)

2. 四大容器总览

表格

容器 底层结构 key 唯一性 有序性 查找效率 适用场景
std::map 红黑树 唯一 按键升序 O(log n) 需要有序 + 唯一 key
std::multimap 红黑树 可重复 按键升序 O(log n) 需要有序 + 重复 key
std::unordered_map 哈希表 唯一 无序 O (1) 平均 追求极致查找速度
std::unordered_multimap 哈希表 可重复 无序 O (1) 平均 追求速度 + 允许重复 key

核心结论:

  • 有序 → 选红黑树系列(map/multimap)
  • 最快查找 → 选哈希表系列(unordered_map)
  • key 不能重复 → 不带 multi 前缀
  • key 可以重复 → 带 multi 前缀

二、std::map(有序唯一键值对)

1. 底层与特性

  • 底层:红黑树(自平衡二叉搜索树)
  • 特性:key 唯一、默认按键升序排列、插入 / 删除 / 查找稳定 O (log n)
  • 头文件:#include <map>

2. 基础用法(最常用)

cpp

运行

#include <iostream>
#include <map>
#include <string>
using namespace std;

int main() {
    // 1. 定义:map<key类型, value类型>
    map<int, string> student;

    // 2. 插入数据(3种方式)
    student[1001] = "张三";        // 最常用:数组式赋值(key不存在则创建)
    student.insert({1002, "李四"}); // insert 插入 pair
    student.insert(make_pair(1003, "王五"));

    // 3. 访问数据
    cout << "学号1001:" << student[1001] << endl; // 直接用key访问
    // 安全访问:避免key不存在时自动创建空元素
    auto it = student.find(1002);
    if (it != student.end()) {
        cout << "学号1002:" << it->second << endl;
    }

    // 4. 遍历(迭代器/范围for)
    cout << "\n全部学生(有序):" << endl;
    for (auto& pair : student) {
        cout << "key:" << pair.first << ",value:" << pair.second << endl;
    }

    // 5. 删除元素
    student.erase(1003); // 按key删除
    // student.erase(it); // 按迭代器删除

    // 6. 常用方法
    cout << "\n元素个数:" << student.size() << endl;
    cout << "是否为空:" << student.empty() << endl;
    student.clear(); // 清空所有元素

    return 0;
}

3. 核心方法速查

表格

方法 作用
map[k] = v 赋值 / 访问(key 不存在会自动创建)
insert({k,v}) 插入键值对(key 重复则插入失败)
find(k) 查找 key,返回迭代器(找不到返回 end ())
erase(k) 删除指定 key 的元素
size() 返回元素个数
empty() 判断是否为空
clear() 清空容器
count(k) 统计 key 出现次数(map 中只能是 0/1)

三、std::multimap(有序可重复键值对)

1. 特性

  • map 唯一区别:key 可以重复
  • 有序、底层红黑树,不支持 [] 运算符(因为 key 不唯一,无法直接索引)
  • 适用场景:一个 key 对应多个 value(如:一个班级对应多个学生)

2. 核心用法

cpp

运行

#include <map>
#include <iostream>
using namespace std;

int main() {
    multimap<string, int> score; // 科目-分数(一个科目可多次录入)

    // 插入重复key
    score.insert({"数学", 90});
    score.insert({"语文", 85});
    score.insert({"数学", 95}); // key重复,允许插入

    // 遍历:重复key会相邻排列
    for (auto& p : score) {
        cout << p.first << ":" << p.second << endl;
    }

    // 查找指定key的所有值(重点)
    auto range = score.equal_range("数学");
    cout << "\n数学所有分数:";
    for (auto it = range.first; it != range.second; ++it) {
        cout << it->second << " ";
    }

    return 0;
}

3. 专属方法

  • equal_range(k):返回 key 对应的所有元素的迭代器区间
  • count(k):返回 key 重复的次数
  • 不支持 [] 运算符!

四、std::unordered_map(无序唯一键值对)

1. 底层与特性

  • 底层:哈希表(散列表)
  • 特性:key 唯一、无序平均查找 O (1)(效率远高于 map)
  • 缺点:占用内存稍大、无顺序、极端情况(哈希冲突)退化为 O (n)
  • 头文件:#include <unordered_map>

2. 用法(与 map 几乎一致)

cpp

运行

#include <unordered_map>
#include <iostream>
using namespace std;

int main() {
    unordered_map<int, string> dict;

    // 插入、访问、遍历用法和map完全相同
    dict[1] = "apple";
    dict[2] = "banana";

    // 遍历:无序输出(顺序不固定)
    for (auto& p : dict) {
        cout << p.first << ":" << p.second << endl;
    }

    return 0;
}

3. 与 map 的核心区别

  1. 效率:unordered_map 查找 / 插入更快(O (1) vs O (log n))
  2. 顺序:map 有序,unordered_map 无序
  3. 内存:哈希表内存占用更高
  4. key 要求:map 支持自定义 key(需重载 <),unordered_map 自定义 key 需提供哈希函数

五、std::unordered_multimap(无序可重复键值对)

  • 组合特性:哈希表 + 无序 + key 可重复
  • 用法:和 multimap 一致,只是无序、效率更高
  • 不支持 [] 运算符,用 equal_range 查找重复 key

六、map 系列高频面试点 & 避坑指南

1. 高频面试问题

  1. map 和 unordered_map 的区别?底层(红黑树 / 哈希表)、有序性、效率、内存、适用场景
  2. 为什么 map 是有序的?底层红黑树会自动按键排序
  3. multimap 为什么不能用 []?key 不唯一,无法确定返回哪个 value
  4. map 插入重复 key 会发生什么?map[key] = v 会覆盖旧值;insert 会插入失败

2. 开发避坑

  1. 不要用 [] 查找 map 元素if (map[100])自动创建 key=100 的空元素,导致容器体积变大✅ 正确写法:用 find()count()
  2. multimap/unordered_multimap 禁止使用 []
  3. 自定义类型作为 key
    • map:需要重载 < 运算符
    • unordered_map:需要提供哈希函数 + 相等判断
  4. 性能选择
    • 数据量小、需要有序 → map
    • 数据量大、追求速度 → unordered_map
    • 需要重复 key → 对应 multi 版本

七、实战选择建议

  1. 90% 业务场景:用 unordered_map(最快、唯一 key)
  2. 需要排序展示 / 遍历:用 map(如排行榜、字典序输出)
  3. 一对多数据:用 multimap/unordered_multimap
  4. 嵌入式 / 内存紧张:优先 map(内存占用低)

总结

  1. map 系列是键值对存储,核心是按键快速查找
  2. 四大容器:有序唯一 (map)、有序重复 (multimap)、无序唯一 (unordered_map)、无序重复 (unordered_multimap)
  3. 底层决定特性:红黑树 = 有序稳定,哈希表 = 超快查找
  4. 开发首选:unordered_map(效率优先),需要有序则用 map
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐