Skip to content

map系列容器详解

map系列容器是STL中核心的关联式容器,与set系列(值为关键字)不同,map以「键值对(key-value)」为存储单元,核心作用是实现“关键字映射”,即通过唯一的key(关键字)对应唯一的value(值),底层基于红黑树实现,支持高效的查找、插入和删除操作,是日常开发和算法题中常用的映射工具。

一、map核心特性

map系列容器主要分为两类:mapunordered_map,与set系列对应,二者核心区别在于「有序性」和「底层实现」,具体特性对比如下:

容器类型有序性关键字(key)是否唯一底层实现核心效率(插入/查找/删除)核心优势
map✅ 是(默认升序)✅ 唯一红黑树(平衡二叉搜索树)O(log n)(稳定)有序映射,支持按key排序、范围查找
unordered_map❌ 否✅ 唯一哈希表O(1)(平均),最坏O(n)查找速度极快,适合高频映射查询

补充:与map对应的“允许重复key”的容器为 multimap(有序)和 unordered_multimap(无序),核心区别是key可重复,value可不同,用法与map基本一致,仅插入和查找时需注意key的重复性。

二、map与set的核心区别

很多初学者会混淆map和set,二者同属关联式容器,但核心用途不同,具体区别如下:

  1. 存储单元不同:set仅存储“值”(value),map存储“键值对(key-value)”;
  2. 核心作用不同:set侧重“去重、排序、查找”,map侧重“关键字映射”(通过key找value);
  3. 关键字不同:set的关键字就是自身的值,map的关键字是独立的key,与value分离。

三、逐一详解:map系列容器用法

1. map:有序、key唯一的键值对映射

map是最常用的map系列容器,key唯一,插入后会自动按key升序排列,支持通过key快速查找、修改对应的value。

基础用法(完整代码)

cpp
#include <iostream>
#include <map>  // map的头文件
using namespace std;

int main() {
    // 1. 定义:key为int类型,value为string类型(默认key升序)
    map<int, string> mp;
    
    // 2. 插入元素(三种方式,推荐前两种)
    mp.insert(pair<int, string>(1, "apple"));  // 方式1:pair插入
    mp.emplace(2, "banana");                   // 方式2:emplace插入(更高效)
    mp[3] = "orange";                          // 方式3:[]赋值插入(不存在则创建,存在则修改)
    
    // 注意:key唯一,重复插入会失败
    mp.insert(pair<int, string>(1, "pear"));  // 重复key,插入无效
    
    // 3. 遍历(自动按key升序)
    cout << "map遍历(按key升序):" << endl;
    for (auto it = mp.begin(); it != mp.end(); it++) {
        // it->first 是key,it->second 是value
        cout << "key:" << it->first << ",value:" << it->second << endl;
    }
    // 输出:
    // key:1,value:apple
    // key:2,value:banana
    // key:3,value:orange
    
    // 4. 查找元素(通过key查找)
    auto find_it = mp.find(2);  // 查找key=2的元素,返回迭代器
    if (find_it != mp.end()) {
        cout << "\n找到key=2,对应的value:" << find_it->second << endl;
    } else {
        cout << "\n未找到key=2" << endl;
    }
    
    // 5. 修改value(通过key修改)
    mp[2] = "grape";  // 直接通过[]修改key对应的value
    cout << "\n修改后key=2的value:" << mp[2] << endl;  // 输出:grape
    
    // 6. 删除元素(三种方式)
    mp.erase(3);                // 方式1:通过key删除
    // mp.erase(find_it);        // 方式2:通过迭代器删除(删除key=2)
    // mp.erase(mp.begin(), mp.end());  // 方式3:删除指定范围元素
    
    // 7. 其他常用操作
    cout << "\nmap中元素个数:" << mp.size() << endl;  // 输出:2(删除了key=3)
    if (mp.empty()) {
        cout << "map为空" << endl;
    } else {
        cout << "map非空" << endl;
    }
    mp.clear();  // 清空map
    return 0;
}

补充:key 降序排列与 set 类似,map 也支持自定义排序,实现 key 降序:

cpp
// 定义降序排序规则
struct cmp {
    bool operator()(const int& a, const int& b) const {
        return a > b;  // key降序
    }
};

map<int, string, cmp> mp;  // 降序map
mp.emplace(1, "apple");
mp.emplace(2, "banana");
// 遍历输出:key:2,value:banana;key:1,value:apple

2. unordered_map:无序、key 唯一的键值对映射

unordered_map 与 map 的核心区别是「无序」,底层基于哈希表实现,查找、插入、删除的平均效率比 map 高,但不支持排序,key 同样唯一。

基础用法(核心代码)

cpp
#include <iostream>
#include <unordered_map>  // unordered_map的头文件
using namespace std;

int main() {
    // 1. 定义:key为string类型,value为int类型(无序)
    unordered_map<string, int> umap;
    
    // 2. 插入元素(与map用法一致)
    umap.emplace("apple", 10);
    umap.emplace("banana", 20);
    umap["orange"] = 15;
    umap.emplace("apple", 12);  // 重复key,插入无效
    
    // 3. 遍历(无序,每次运行顺序可能不同)
    cout << "unordered_map遍历(无序):" << endl;
    for (auto& pair : umap) {
        cout << "key:" << pair.first << ",value:" << pair.second << endl;
    }
    // 示例输出(顺序不固定):
    // key:banana,value:20
    // key:apple,value:10
    // key:orange,value:15
    
    // 4. 查找、修改、删除(与map用法一致)
    auto find_it = umap.find("orange");
    if (find_it != umap.end()) {
        cout << "\n找到key=orange,value:" << find_it->second << endl;
    }
    umap["orange"] = 18;  // 修改value
    umap.erase("banana"); // 删除key=banana
    
    // 5. 其他常用操作
    cout << "\nunordered_map元素个数:" << umap.size() << endl;  // 输出:2
    umap.clear();
    return 0;
}

3. multimap:有序、key 可重复的键值对映射

multimap 与 map 的核心区别是「key 可重复」,底层同样是红黑树,支持按 key 升序排列,适合需要多个相同 key 对应不同 value 的场景(如:一个学生对应多门课程成绩)。

基础用法(核心代码)

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

int main() {
    multimap<string, int> mmp;  // key可重复,有序
    
    // 插入相同key的不同value
    mmp.emplace("张三", 90);
    mmp.emplace("张三", 85);
    mmp.emplace("李四", 95);
    
    // 遍历(按key升序,相同key的value按插入顺序排列)
    cout << "multimap遍历:" << endl;
    for (auto& pair : mmp) {
        cout << "key:" << pair.first << ",value:" << pair.second << endl;
    }
    // 输出:
    // key:张三,value:90
    // key:张三,value:85
    // key:李四,value:95
    
    // 统计相同key的个数
    cout << "\n张三的成绩个数:" << mmp.count("张三") << endl;  // 输出:2
    
    // 查找所有key=张三的元素
    auto range = mmp.equal_range("张三");
    cout << "\n张三的所有成绩:";
    for (auto it = range.first; it != range.second; it++) {
        cout << it->second << " ";
    }
    cout << endl;  // 输出:90 85
    
    return 0;
}

4. unordered_multimap:无序、key 可重复的键值对映射

unordered_multimap 与 unordered_map 的核心区别是「key 可重复」,底层基于哈希表实现,无序,适合需要快速统计相同 key 对应多个 value 的场景,用法与 multimap 类似,仅无排序功能。

四、常用操作汇总(map 系列通用)

操作语法说明
插入insert(pair) / emplace(key, value) / [key] = valueemplace 效率最高,[] 可用于插入和修改
查找find(key)返回指向该 key 的迭代器,找不到返回 end ()
统计个数count(key)返回该 key 的个数(map/unordered_map 只能是 0 或 1)
修改 valuemap[key] = new_value仅 map/unordered_map 支持,multimap 需通过迭代器修改
删除erase (key) /erase (迭代器) /erase (范围)按 key 删除时,multimap 会删除所有该 key 的元素
清空clear()清空所有键值对
判空empty()为空返回 true,否则返回 false
获取大小size()返回键值对的个数

五、适用场景总结(一句话选型)

有序映射、key 唯一 → 用 map(如:用户 ID 对应用户名,需要按 ID 排序); 快速映射、key 唯一、不在乎顺序 → 用 unordered_map(效率最优,如:缓存映射、快速查询); 有序映射、key 可重复 → 用 multimap(如:一个 key 对应多个 value,需要排序); 快速映射、key 可重复、不在乎顺序 → 用 unordered_multimap(如:统计相同 key 的多个 value)。

六、注意事项

map 系列容器的 key 是不可修改的(底层红黑树 / 哈希表依赖 key 排序 / 哈希),若需修改 key,需先删除旧 key,再插入新 key; unordered_map 的 key 需要支持哈希函数,自定义类型作为 key 时,需重写哈希函数和 == 运算符; multimap 不支持 [] 操作符(因为 key 可重复,无法确定对应哪个 value),修改 value 需通过迭代器; 头文件区分:map、multimap 包含 <map>;unordered_map、unordered_multimap 包含 <unordered_map>

百炼成钢,融会贯通