3 条题解

  • 1
    @ 2026-1-17 22:35:51

    C++ STL unordered_map 方法和用法指南

    概述

    unordered_map 是 C++ STL 中的哈希表实现,提供平均 O(1) 的查找、插入和删除性能。


    主要方法

    1. 构造和析构

    #include <unordered_map>
    
    unordered_map<int, string> map1;                    // 默认构造
    unordered_map<int, string> map2(map1);              // 拷贝构造
    unordered_map<int, string> map3 = {{1, "a"}, {2, "b"}};  // 初始化列表构造
    

    2. 元素访问

    unordered_map<int, string> map;
    map[1] = "apple";
    map[2] = "banana";
    
    // at() - 访问,键不存在时抛出 out_of_range 异常
    string val = map.at(1);  // "apple"
    // string val2 = map.at(3);  // 抛出异常
    
    // operator[] - 访问或插入
    string val = map[1];     // "apple"
    map[3] = "cherry";       // 如果键不存在,则插入默认值后赋值
    

    3. 查找元素

    unordered_map<int, string> map = {{1, "a"}, {2, "b"}};
    
    // find() - 返回迭代器
    auto it = map.find(1);
    if (it != map.end()) {
        cout << it->first << ": " << it->second << endl;  // 1: a
    } else {
        cout << "Not found" << endl;
    }
    
    // count() - 返回 0 或 1(unordered_map 中无重复键)
    if (map.count(2) > 0) {
        cout << "Key 2 exists" << endl;
    }
    
    // contains() - C++20 标准
    if (map.contains(1)) {
        cout << "Key 1 exists" << endl;
    }
    

    4. 插入元素

    unordered_map<int, string> map;
    
    // insert() - 插入单个键值对
    map.insert({1, "apple"});
    map.insert(make_pair(2, "banana"));
    
    // insert() - 插入范围
    unordered_map<int, string> map2 = {{3, "cherry"}, {4, "date"}};
    map.insert(map2.begin(), map2.end());
    
    // emplace() - 就地构造插入,通常更高效
    map.emplace(5, "elderberry");
    
    // 检查插入是否成功
    auto result = map.insert({1, "new_apple"});
    if (!result.second) {
        cout << "Key 1 already exists, insertion failed" << endl;
    }
    

    operator[] vs insert() 的区别

    特性 operator[] insert()
    键不存在时 创建新项,值初始化为默认值 返回 pair,可判断是否插入成功
    键已存在时 覆盖旧值 不覆盖,保持原值
    返回值 引用(对值的引用) pair<iterator, bool>
    能否判断是否成功
    效率 快(直接访问或插入) 快(但需要检查返回值)
    适用场景 赋值、更新 仅插入新元素、批量插入、判断插入结果

    实际代码对比

    unordered_map<int, string> map;
    
    // 场景 1:想插入,但不想覆盖已有的值
    // 用 operator[] 实现:无法判断是否覆盖
    map[10] = "first";
    map[10] = "second";  // 覆盖了原值,但你无法察觉
    
    // 用 insert() 实现:可以明确知道
    auto result = map.insert({10, "first"});
    if (result.second) {
        cout << "插入成功" << endl;
    } else {
        cout << "键已存在,插入失败,原值为: " << result.first->second << endl;
    }
    
    // 场景 2:想批量插入
    vector<pair<int, string>> data = {{1, "a"}, {2, "b"}, {3, "c"}};
    // operator[] 无法直接批量操作
    // insert() 可以 :
    map.insert(data.begin(), data.end());
    
    // 场景 3:只想访问,不想创建新元素
    int key = 999;
    // 用 operator[] 会创建新元素,改变 map 的大小
    // map[999];  // 这会在 map 中创建 999 这个键
    
    // 用 find() 或 count() :
    if (map.count(999)) {
        cout << map[999] << endl;
    } else {
        cout << "键不存在" << endl;
    }
    

    总结

    • operator[]: 适合做值的赋值和更新,简洁直观
    • insert() / emplace(): 适合仅插入新元素,且需要判断是否插入成功的场景
    • find() / count() / at(): 适合仅查询,不想修改 map 的场景

    5. 删除元素

    unordered_map<int, string> map = {{1, "a"}, {2, "b"}, {3, "c"}};
    
    // erase() - 按键删除
    map.erase(1);
    
    // erase() - 按迭代器删除
    auto it = map.find(2);
    if (it != map.end()) {
        map.erase(it);
    }
    
    // erase() - 删除范围
    auto it1 = map.find(1);
    auto it2 = map.find(3);
    map.erase(it1, it2);
    
    // clear() - 清空所有元素
    map.clear();
    

    6. 容量和大小

    unordered_map<int, string> map = {{1, "a"}, {2, "b"}, {3, "c"}};
    
    // size() - 返回元素个数
    cout << map.size() << endl;  // 3
    
    // empty() - 检查是否为空
    if (map.empty()) {
        cout << "Map is empty" << endl;
    } else {
        cout << "Map is not empty" << endl;
    }
    
    // max_size() - 返回理论最大元素个数
    cout << map.max_size() << endl;
    

    7. 迭代器

    unordered_map<int, string> map = {{1, "a"}, {2, "b"}, {3, "c"}};
    
    // begin() 和 end()
    for (auto it = map.begin(); it != map.end(); ++it) {
        cout << it->first << ": " << it->second << endl;
    }
    
    // 范围 for 循环(推荐)- C++17 结构化绑定
    for (auto& [key, value] : map) {
        cout << key << ": " << value << endl;
    }
    
    // C++14 及以下兼容写法
    for (auto& p : map) {
        cout << p.first << ": " << p.second << endl;
    }
    
    // cbegin() 和 cend() - 常量迭代器
    for (auto it = map.cbegin(); it != map.cend(); ++it) {
        cout << it->first << ": " << it->second << endl;
    }
    

    C++14 兼容性说明

    CSP/NOI比赛限制只能用C++14标准

    写法 C++14 C++17+ 说明
    for (auto it = map.begin(); ...) 传统迭代器遍历,所有版本都支持
    for (auto& p : map) 范围 for 循环,C++11 起支持
    for (auto& [key, value] : map) 结构化绑定,需要 C++17

    不同 C++ 版本的写法对比

    unordered_map<int, string> map = {{1, "a"}, {2, "b"}};
    
    // C++14 及以下 - 推荐写法
    for (auto& p : map) {
        int key = p.first;
        string value = p.second;
        cout << key << ": " << value << endl;
    }
    
    // C++14 - 另一种写法(不推荐,冗长)
    for (const auto& pair : map) {
        cout << pair.first << ": " << pair.second << endl;
    }
    
    // C++17+ - 最简洁写法(使用结构化绑定)
    for (auto& [key, value] : map) {
        cout << key << ": " << value << endl;
    }
    
    // C++11 - 传统迭代器写法
    for (auto it = map.begin(); it != map.end(); ++it) {
        cout << it->first << ": " << it->second << endl;
    }
    

    8. 桶相关操作

    unordered_map<int, string> map = {{1, "a"}, {2, "b"}};
    
    // bucket_count() - 返回桶的数量
    cout << "Bucket count: " << map.bucket_count() << endl;
    
    // load_factor() - 返回负载因子 (元素数 / 桶数)
    cout << "Load factor: " << map.load_factor() << endl;
    
    // max_load_factor() - 获取或设置最大负载因子
    cout << "Max load factor: " << map.max_load_factor() << endl;
    map.max_load_factor(0.75);
    
    // rehash() - 重新哈希,指定桶的数量
    map.rehash(100);
    

    完整示例

    #include <iostream>
    #include <unordered_map>
    using namespace std;
    
    int main() {
        unordered_map<int, string> students;
        
        // 添加元素
        students[1001] = "Alice";
        students[1002] = "Bob";
        students.emplace(1003, "Charlie");
        
        // 遍历
        cout << "All students:" << endl;
        for (auto& [id, name] : students) {
            cout << "ID: " << id << ", Name: " << name << endl;
        }
        
        // 查找
        if (students.count(1002)) {
            cout << "Student 1002: " << students[1002] << endl;
        }
        
        // 更新
        students[1001] = "Alice (updated)";
        
        // 删除
        students.erase(1003);
        
        cout << "Remaining students: " << students.size() << endl;
        
        return 0;
    }
    

    输出:

    All students:
    ID: 1003, Name: Charlie
    ID: 1001, Name: Alice
    ID: 1002, Name: Bob
    Student 1002: Bob
    Remaining students: 2
    

    常见用途

    用途 代码
    频率统计 unordered_map<char, int> freq; freq[ch]++;
    键值映射 unordered_map<string, int> mapping; mapping["age"] = 25;
    缓存 if (cache.count(key)) return cache[key];
    去重 unordered_map<int, bool> seen; if (!seen[x]) seen[x] = true;

    频率:数学统计术语,指某个值出现的次数

    信息

    ID
    19385
    时间
    1000ms
    内存
    128MiB
    难度
    10
    标签
    (无)
    递交数
    5
    已通过
    4
    上传者