C++中的unordered_map容器详解

C++中的unordered_map容器详解

1. unordered_map概述

unordered_map是C++11引入的关联容器,基于哈希表实现,存储键值对(key-value pairs),提供快速的查找、插入和删除操作,平均时间复杂度为O(1)O(1)O(1)。

2. 基本特性

  • 哈希表实现:使用哈希函数组织键值对
  • 唯一键:每个键只能出现一次
  • 无序存储:元素不以任何特定顺序存储
  • 快速访问:平均情况下提供常数时间复杂度的查找
  • 动态大小:可以根据需要自动扩展

3. 头文件与声明

cpp 复制代码
#include <unordered_map>
using namespace std;

unordered_map<int, string> um1;                     // 空unordered_map
unordered_map<string, double> um2 = {{"pi", 3.14}, {"e", 2.71}}; // 初始化列表
unordered_map<char, int> um3(10);                  // 初始桶数为10

4. 构造函数与初始化

4.1 默认构造

cpp 复制代码
unordered_map<string, int> wordCount;

4.2 范围构造

cpp 复制代码
pair<string, int> arr[] = {{"apple", 5}, {"banana", 3}};
unordered_map<string, int> fruitCount(arr, arr+2);

4.3 拷贝构造

cpp 复制代码
unordered_map<string, int> um2(um1);

4.4 自定义哈希函数和相等比较

cpp 复制代码
struct CaseInsensitiveHash {
    size_t operator()(const string& s) const {
        size_t h = 0;
        for(char c : s) {
            h += tolower(c);
        }
        return h;
    }
};

struct CaseInsensitiveEqual {
    bool operator()(const string& a, const string& b) const {
        if(a.length() != b.length()) return false;
        for(size_t i = 0; i < a.length(); ++i) {
            if(tolower(a[i]) != tolower(b[i])) return false;
        }
        return true;
    }
};

unordered_map<string, int, CaseInsensitiveHash, CaseInsensitiveEqual> case_insensitive_map;

5. 容量操作

5.1 size()

cpp 复制代码
cout << um.size();  // 返回键值对数量

5.2 empty()

cpp 复制代码
if(um.empty()) {
    cout << "unordered_map is empty";
}

5.3 max_size()

cpp 复制代码
cout << um.max_size();  // 返回可容纳的最大键值对数

6. 元素访问

6.1 operator[]

cpp 复制代码
um["apple"] = 5;       // 插入或修改键"apple"对应的值
int count = um["apple"]; // 访问键"apple"对应的值

6.2 at()

cpp 复制代码
try {
    int val = um.at("orange"); // 访问键"orange"对应的值(边界检查)
} catch(const out_of_range& e) {
    cerr << "Key not found: " << e.what() << endl;
}

6.3 迭代器访问

cpp 复制代码
for(auto it = um.begin(); it != um.end(); ++it) {
    cout << it->first << ": " << it->second << endl;
}

7. 修改操作

7.1 insert()

cpp 复制代码
um.insert({"banana", 3});                  // 插入单个键值对
um.insert({{"pear", 2}, {"orange", 4}});   // 插入初始化列表
auto result = um.insert(make_pair("apple", 6)); // 返回pair<iterator, bool>

7.2 emplace()

cpp 复制代码
auto result = um.emplace("grape", 7);      // 原地构造键值对

7.3 erase()

cpp 复制代码
um.erase("apple");                         // 删除键"apple"对应的键值对
auto it = um.find("banana");
if(it != um.end()) {
    um.erase(it);                          // 通过迭代器删除
}
um.erase(um.begin(), um.end());            // 删除范围

7.4 clear()

cpp 复制代码
um.clear();  // 清空所有键值对

7.5 swap()

cpp 复制代码
unordered_map<string, int> um2;
um.swap(um2);  // 交换两个unordered_map

8. 查找操作

8.1 find()

cpp 复制代码
auto it = um.find("apple");  // 返回指向键"apple"的迭代器
if(it != um.end()) {
    cout << "Found: " << it->second;
}

8.2 count()

cpp 复制代码
cout << um.count("banana");  // 返回键"banana"的数量(0或1)

8.3 equal_range()

cpp 复制代码
auto range = um.equal_range("apple");  // 返回等于"apple"的键值对范围

9. 桶操作

9.1 bucket_count()

cpp 复制代码
cout << um.bucket_count();  // 返回桶的数量

9.2 `max_bucket_count()

cpp 复制代码
cout << um.max_bucket_count();  // 返回最大桶数

9.3 bucket_size()

cpp 复制代码
cout << um.bucket_size(2);  // 返回第2个桶中的键值对数

9.4 bucket()

cpp 复制代码
cout << um.bucket("apple");  // 返回"apple"所在的桶索引

10. 哈希策略

10.1 load_factor()

cpp 复制代码
cout << um.load_factor();  // 返回负载因子(键值对数/桶数)

10.2 max_load_factor()

cpp 复制代码
cout << um.max_load_factor();  // 返回最大负载因子
um.max_load_factor(0.75);      // 设置最大负载因子

10.3 rehash()

cpp 复制代码
um.rehash(20);  // 设置桶数为至少20

10.4 reserve()

cpp 复制代码
um.reserve(100);  // 预留空间至少容纳100个键值对

11. 完整示例

cpp 复制代码
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;

int main() {
    // 创建并初始化unordered_map
    unordered_map<string, int> wordCount = {
        {"apple", 5},
        {"banana", 3},
        {"orange", 2}
    };
    
    // 插入元素
    wordCount.insert({"grape", 4});
    wordCount.emplace("pear", 1);
    wordCount["kiwi"] = 6;  // 使用operator[]插入
    
    // 修改元素
    wordCount["apple"] += 2;
    
    // 查找元素
    if(wordCount.find("banana") != wordCount.end()) {
        cout << "Banana count: " << wordCount["banana"] << endl;
    }
    
    // 遍历unordered_map
    cout << "All word counts:" << endl;
    for(const auto& pair : wordCount) {
        cout << pair.first << ": " << pair.second << endl;
    }
    
    // 删除元素
    wordCount.erase("orange");
    auto it = wordCount.find("pear");
    if(it != wordCount.end()) {
        wordCount.erase(it);
    }
    
    // 桶信息
    cout << "\nBucket information:" << endl;
    cout << "Number of buckets: " << wordCount.bucket_count() << endl;
    cout << "Current load factor: " << wordCount.load_factor() << endl;
    
    // 调整哈希表
    wordCount.rehash(10);
    cout << "After rehash, bucket count: " << wordCount.bucket_count() << endl;
    
    // 容量信息
    cout << "\nSize: " << wordCount.size() << endl;
    cout << "Is empty: " << (wordCount.empty() ? "Yes" : "No") << endl;
    
    return 0;
}

12. 性能提示

  1. 平均情况下查找、插入、删除时间复杂度为O(1)O(1)O(1)
  2. 最坏情况下(哈希冲突严重)时间复杂度退化为O(n)O(n)O(n)
  3. 负载因子过高会影响性能,可适时rehash()
  4. 自定义键类型需要提供哈希函数和相等比较
  5. 迭代器在插入操作后可能失效(重新哈希时)

13. 与map比较

特性 unordered_map map
实现方式 哈希表 红黑树
元素顺序 无序 按键排序
查找复杂度 平均O(1)O(1)O(1) O(log⁡2n)O(\log_2 n)O(log2n)
内存使用 通常较少 通常较多
迭代器稳定性 插入可能失效 稳定(除删除元素)
相关推荐
ZHOUPUYU6 小时前
PHP 8.3网关优化:我用JIT将QPS提升300%的真实踩坑录
开发语言·php
寻寻觅觅☆10 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
fpcc10 小时前
并行编程实战——CUDA编程的Parallel Task类型
c++·cuda
l1t10 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
赶路人儿11 小时前
Jsoniter(java版本)使用介绍
java·开发语言
ceclar12311 小时前
C++使用format
开发语言·c++·算法
码说AI12 小时前
python快速绘制走势图对比曲线
开发语言·python
Gofarlic_OMS12 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
lanhuazui1012 小时前
C++ 中什么时候用::(作用域解析运算符)
c++
charlee4412 小时前
从零实现一个生产级 RAG 语义搜索系统:C++ + ONNX + FAISS 实战
c++·faiss·onnx·rag·语义搜索