C++ STL 入门:map 键值对容器

C++ STL 入门:map 键值对容器


一、核心特性与适用场景

map 是 C++ STL 提供的关联式键值容器,基于红黑树实现,具备以下核心特征:

特性 表现形式 底层原理
键唯一性 不允许重复键值 红黑树节点键值唯一约束
自动排序 元素按键升序排列 红黑树中序遍历特性
对数复杂度 插入/查找/删除均为 O(log n) 树高平衡特性保障

典型应用场景

  • 字典统计(如词频统计)
  • 有序数据映射(如时间序列数据)
  • 配置管理(键值对存储)
  • 关联容器组合(与vector/set配合)

二、基础操作与代码演示
1. 容器初始化
cpp 复制代码
#include <iostream>
#include <map>
using namespace std;

int main() {
    // 默认构造:空映射
    map<string, int> m; 

    // 初始化列表构造(C++11)
    map<string, int> m2 = {
        {"hello", 4}, 
        {"world", 3}, 
        {"ilovewuhan", 5}
    };
2. 元素操作全流程
cpp 复制代码
    // 插入操作
    m["hello"] = 4;     // 插入键值对
    m["world"] = 3; 
    m["ilovewuhan"] = 5;
    m["ha"] = 1;        // 支持中文键值(字符串编码需统一)

    // 下标访问(注意副作用)
    cout << "hello : " << m["hello"] << endl; // 输出4

    // 安全访问示范
    if(m.find("cpp") != m.end()) {
        cout << m.at("cpp"); // 不存在时抛出out_of_range
    }

    // 迭代器遍历
    for(auto it = m.begin(); it != m.end(); ++it){
        cout << it->first << ":" << it->second << " ";
    } // 输出按键排序:ha hello ilovewuhan world

    // 获取容器大小
    cout << "\nmap的长度为: " << m.size() << endl; // 输出4

三、操作时间复杂度分析
操作类型 时间复杂度 特性说明
insert() O(log n) 需要平衡树结构调整
erase() O(log n) 同样涉及树重构
find() O(log n) 二分查找特性
operator[] O(log n) 不存在时自动插入默认值
at() O(log n) 带异常检查的安全访问
遍历 O(n) 中序遍历完整红黑树

四、进阶用法与技巧
1. 自定义排序规则
cpp 复制代码
// 创建降序map(按字符串长度排序)
struct cmp {
    bool operator()(const string& a, const string& b) const {
        return a.size() < b.size(); // 按键长排序
    }
};
map<string, int, cmp> m3;

m3["a"] = 1; 
m3["longer"] = 2; 
m3["mid"] = 3;

// 遍历顺序:a → mid → longer
2. 批量操作优化
cpp 复制代码
// 范围删除
auto start = m.lower_bound("h"); // >=h的第一个键
auto end = m.upper_bound("w");   // >w的第一个键
m.erase(start, end); // 删除所有h ≤ key < w的键值对

// 合并操作(C++17)
map<string, int> src{{"x",10}, {"y",20}};
m.merge(src); // 将src中的元素移动到m中
3. 节点控制(C++17)
cpp 复制代码
// 提取节点修改键
auto nh = m.extract("ilovewuhan"); 
nh.key() = "newkey"; // 修改键值(必须保持排序不变!)
m.insert(move(nh));  // 重新插入

// 节点拼接(零拷贝转移)
map<string, int> m4;
m4.insert(m.extract(m.begin())); // 将首个节点转移到m4

五、易错点与解决方案
错误类型 典型表现 解决方案
意外插入 m["nonexist"]返回0 优先使用find()检查
排序规则错误 自定义比较器未满足严格弱序 遵循运算符重载规范
迭代器失效 遍历时删除元素 使用erase()返回新迭代器
多线程竞争 并发读写未加锁 使用std::mutex保护

安全访问示例

cpp 复制代码
int get_value(const map<string, int>& m, const string& key) {
    auto it = m.find(key);
    if(it != m.end()) return it->second;
    throw invalid_argument("Key not found");
}

六、性能优化技巧
  1. 空间预留优化(C++11)
cpp 复制代码
m.max_size(); // 查询最大容量
m.rehash(100); // 预留足够哈希桶(unordered_map用法)
  1. 插入效率优化
cpp 复制代码
// 使用emplace原地构造
m.emplace("newkey", 42); // 避免临时对象生成

// 批量插入优化
vector<pair<string, int>> vec = { /*...*/ };
m.insert(vec.begin(), vec.end()); // 批量插入O(n log n)
  1. 内存收缩技巧
cpp 复制代码
// 清空并释放内存
map<string, int>(m).swap(m); 

// 合并后收缩
m.merge(m2);
map<string, int>(m).swap(m); 

七、知识延伸与对比
容器类型 键唯一性 查找效率 排序特性 典型应用场景
map O(log n) 自动升序 有序键值对存储
unordered_map O(1)平均 无序 快速查找
multimap O(log n) 允许重复键 一对多关系映射
set N/A O(log n) 仅存储键 数据去重

配套练习项目
LeetCode Map相关题目
CppReference map文档

相关推荐
wow_DG21 分钟前
【C++✨】多种 C++ 解法固定宽度右对齐输出(每个数占 8 列)
开发语言·c++·算法
Epiphany.55631 分钟前
c++最长上升子序列长度
c++·算法·图论
颖川守一2 小时前
C++c6-类和对象-封装-设计案例2-点和圆的关系
开发语言·c++
charlee442 小时前
将std容器的正向迭代器转换成反向迭代器
c++
arbboter3 小时前
【C++20】新特性探秘:提升现代C++开发效率的利器
c++·c++20·新特性·span·结构化绑定·初始化变量·模板参数推导
zc.ovo3 小时前
图论水题4
c++·算法·图论
眠りたいです3 小时前
Qt音频播放器项目实践:文件过滤、元数据提取与动态歌词显示实现
c++·qt·ui·音视频·媒体·qt5·mime
汤永红4 小时前
week2-[循环嵌套]数位和为m倍数的数
c++·算法·信睡奥赛
1白天的黑夜16 小时前
前缀和-560.和为k的子数组-力扣(LeetCode)
c++·leetcode·前缀和
No0d1es13 小时前
电子学会青少年软件编程(C/C++)5级等级考试真题试卷(2024年6月)
c语言·c++·算法·青少年编程·电子学会·五级