当前位置: 首页 > news >正文

C++ STL map

文章目录

  • C++ STL `map` 详解
    • 1. `std::map` 的特性
    • 2. 包含头文件
    • 3. 声明和初始化 `std::map`
    • 4. 常用成员函数
      • 4.1 元素访问
      • 4.2 容量
      • 4.3 修改容器
      • 4.4 查找元素
      • 4.5 遍历映射
      • 4.6 其他常用函数
    • 5. 使用示例
    • 6. 注意事项
    • 7. 与其他关联容器的比较
    • 总结

C++ STL map 详解

在 C++ 标准模板库(STL)中,std::map 是一种关联容器,用于存储键值对(key-value pairs),其中每个键在容器中是唯一的。std::map 基于平衡二叉树(通常是红黑树)实现,提供了高效的查找、插入和删除操作。下面将详细介绍 std::map 的特性、常用成员函数以及使用示例。

1. std::map 的特性

  • 键值对存储:每个元素都是一个键值对,形式为 std::pair<const Key, T>,其中 Key 是键的类型,T 是值的类型。
  • 唯一键:容器中的每个键都是唯一的,不能有重复的键。
  • 有序存储:元素按键的顺序自动排序,默认是升序。也可以自定义比较函数来改变排序方式。
  • 底层实现:通常基于平衡二叉树(如红黑树)实现,保证了操作的对数时间复杂度。
  • 不允许修改键:由于键用于维护内部结构,std::map 不允许修改已存在元素的键。

2. 包含头文件

使用 std::map 需要包含 <map> 头文件:

#include <map>

3. 声明和初始化 std::map

#include <map>
#include <string>
#include <iostream>

int main() {
    // 声明一个空的整数到字符串的映射
    std::map<int, std::string> ageMap;

    // 使用初始化列表声明并初始化映射
    std::map<std::string, int> scoreMap = {
        {"Alice", 90},
        {"Bob", 85},
        {"Charlie", 95}
    };

    // 声明一个具有相同键值对的映射
    std::map<std::string, int> anotherScoreMap(scoreMap);

    return 0;
}

4. 常用成员函数

4.1 元素访问

  • operator[]:通过键访问对应的值。如果键不存在,则插入该键并赋予默认值。
  • at(const Key& key):通过键访问对应的值。如果键不存在,抛出 std::out_of_range 异常。
std::map<std::string, int> scoreMap = {{"Alice", 90}, {"Bob", 85}};

// 使用 operator[]
std::cout << "Alice 的分数: " << scoreMap["Alice"] << std::endl; // 输出 90
scoreMap["Charlie"] = 95; // 插入新键值对

// 使用 at()
try {
    std::cout << "Bob 的分数: " << scoreMap.at("Bob") << std::endl; // 输出 85
    std::cout << "David 的分数: " << scoreMap.at("David") << std::endl; // 抛出异常
} catch (const std::out_of_range& e) {
    std::cerr << "异常: " << e.what() << std::endl;
}

4.2 容量

  • empty():检查映射是否为空。
  • size():返回映射中的元素数量。
  • max_size():返回映射可能包含的最大元素数量。
if (scoreMap.empty()) {
    std::cout << "scoreMap 为空。" << std::endl;
} else {
    std::cout << "scoreMap 大小: " << scoreMap.size() << std::endl; // 输出 3
}

4.3 修改容器

  • insert(const value_type& value)emplace(Args&&... args):插入元素。
  • erase(iterator position)erase(const Key& key):移除元素。
  • clear():移除所有元素。
// 插入元素
scoreMap.insert({"David", 88});
scoreMap.emplace("Eve", 92);

// 通过键删除元素
scoreMap.erase("Bob");

// 通过迭代器删除元素
auto it = scoreMap.find("Alice");
if (it != scoreMap.end()) {
    scoreMap.erase(it);
}

// 清空映射
scoreMap.clear();

4.4 查找元素

  • find(const Key& key):返回指向键的迭代器,如果键不存在,则返回 map.end()
  • count(const Key& key):返回键出现的次数(对于 std::map 来说,只能是 0 或 1)。
if (scoreMap.find("Alice") != scoreMap.end()) {
    std::cout << "找到 Alice。" << std::endl;
} else {
    std::cout << "未找到 Alice。" << std::endl;
}

if (scoreMap.count("Bob") > 0) {
    std::cout << "找到 Bob。" << std::endl;
} else {
    std::cout << "未找到 Bob。" << std::endl;
}

4.5 遍历映射

可以使用迭代器或范围-based for 循环(C++11 及以上)来遍历 std::map

for (const auto& pair : scoreMap) {
    std::cout << pair.first << " 的分数: " << pair.second << std::endl;
}

// 使用迭代器
for (auto it = scoreMap.begin(); it != scoreMap.end(); ++it) {
    std::cout << it->first << " 的分数: " << it->second << std::endl;
}

4.6 其他常用函数

  • lower_bound(const Key& key):返回指向第一个不小于给定键的元素的迭代器。
  • upper_bound(const Key& key):返回指向第一个大于给定键的元素的迭代器。
  • equal_range(const Key& key):返回一对迭代器,表示等于给定键的所有元素范围(对于 std::map 来说,最多只有一个元素)。
  • swap(map& other):交换两个映射的内容。
// 插入一些元素
scoreMap["Alice"] = 90;
scoreMap["Bob"] = 85;
scoreMap["Charlie"] = 95;

// 使用 lower_bound
auto low = scoreMap.lower_bound("Bob");
if (low != scoreMap.end()) {
    std::cout << "第一个不小于 Bob 的键: " << low->first << std::endl;
}

// 使用 upper_bound
auto up = scoreMap.upper_bound("Bob");
if (up != scoreMap.end()) {
    std::cout << "第一个大于 Bob 的键: " << up->first << std::endl;
}

// 使用 equal_range
auto range = scoreMap.equal_range("Charlie");
if (range.first != range.second) {
    std::cout << "找到 Charlie 的分数: " << range.first->second << std::endl;
}

// 交换两个映射
std::map<std::string, int> anotherMap = {{"Dave", 80}};
scoreMap.swap(anotherMap);

5. 使用示例

下面给出一个综合示例,展示如何使用 std::map 进行基本操作:

#include <iostream>
#include <map>
#include <string>

int main() {
    // 创建并初始化映射
    std::map<std::string, int> inventory = {
        {"苹果", 50},
        {"香蕉", 30},
        {"橘子", 20}
    };

    // 输出初始库存
    std::cout << "初始库存:" << std::endl;
    for (const auto& item : inventory) {
        std::cout << item.first << ": " << item.second << std::endl;
    }

    // 添加新商品
    inventory["葡萄"] = 40;
    std::cout << "\n添加葡萄后:" << std::endl;
    for (const auto& item : inventory) {
        std::cout << item.first << ": " << item.second << std::endl;
    }

    // 更新商品数量
    inventory["香蕉"] = 35;
    std::cout << "\n更新香蕉数量后:" << std::endl;
    for (const auto& item : inventory) {
        std::cout << item.first << ": " << item.second << std::endl;
    }

    // 删除商品
    inventory.erase("橘子");
    std::cout << "\n删除橘子后:" << std::endl;
    for (const auto& item : inventory) {
        std::cout << item.first << ": " << item.second << std::endl;
    }

    // 查找商品
    std::string searchItem = "苹果";
    if (inventory.find(searchItem) != inventory.end()) {
        std::cout << "找到 " << searchItem << ",数量: " << inventory[searchItem] << std::endl;
    } else {
        std::cout << "未找到 " << searchItem << std::endl;
    }

    // 遍历并打印所有商品
    std::cout << "所有库存商品:" << std::endl;
    for (const auto& item : inventory) { // 替换结构化绑定
        std::cout << item.first << ": " << item.second << std::endl;
    }

    return 0;
}

输出:
在这里插入图片描述

6. 注意事项

  • 键的唯一性std::map 中的每个键都是唯一的,插入重复的键会覆盖原有的值。

  • 有序性:元素按键自动排序,默认是升序。可以通过自定义比较函数改变排序方式。

    struct Compare {
        bool operator()(const std::string& a, const std::string& b) const {
            return a > b; // 降序排列
        }
    };
    
    std::map<std::string, int, Compare> descendingMap = {{"apple", 1}, {"banana", 2}};
    // descendingMap 将按降序排列键
    
  • 性能std::map 的插入、删除和查找操作的时间复杂度为 O(log n),适用于需要有序存储且频繁查找的场景。

  • 内存开销:相比 std::unordered_mapstd::map 通常有更高的内存开销,因为它需要维护元素的顺序。

7. 与其他关联容器的比较

特性std::mapstd::unordered_mapstd::multimap
键的唯一性唯一唯一允许重复键
排序有序(默认升序)无序有序(默认升序)
底层实现平衡二叉树(如红黑树)哈希表平衡二叉树(如红黑树)
查找时间复杂度O(log n)平均 O(1),最坏情况 O(n)O(log n)
插入/删除时间复杂度O(log n)平均 O(1),最坏情况 O(n)O(log n)
元素遍历顺序按键排序无特定顺序按键排序

根据具体需求选择合适的关联容器。例如,如果需要快速查找且不关心元素的顺序,std::unordered_map 是更好的选择;如果需要元素有序存储,std::map 更为合适。

总结

std::map 是 C++ STL 中一个功能强大的关联容器,适用于需要存储键值对且键唯一的场景。它提供了高效的查找、插入和删除操作,并自动维护元素的有序性。了解其特性和常用成员函数,可以帮助我们更高效地编写代码。在实际应用中,应该根据具体需求选择最合适的容器类型。
当然,map容器除了这些之外,还有其他的用法,可以在实践的过程中逐渐摸索,及时记录,便于之后的工作。

相关文章:

  • 模板字面量标签函数
  • pyqt 上传文件或者文件夹打包压缩文件并添加密码并将密码和目标文件信息保存在json文件
  • ccf3401矩阵重塑(其一)
  • 使用Ajax技术进行动态网页的爬虫(pycharm)
  • Linux驱动学习笔记(二)
  • 工作记录 2017-01-25
  • FlinkCDC 达梦数据库实时同步详解
  • 酵母生产二氢槲皮素-文献精读117
  • C++基础系列【24】STL迭代器和算法
  • 基于金融产品深度学习推荐算法详解【附源码】
  • 计算机视觉常见的算法
  • JSON数据格式介绍
  • 蓝耘智算|从静态到动态:探索Maas平台海螺AI图片生成视频功能的强大能力
  • 移动端开发基础与常见布局
  • 网络安全一CTF入门
  • Vala教程-第一个程序(Hello world)
  • Python 视频爬取教程
  • 【通义千问】蓝耘智算 | 智启未来:蓝耘MaaS×通义QwQ-32B引领AI开发生产力
  • Blender选择循环边/循环面技巧
  • 【失败了】LazyGraphRAG利用本地ollama提供Embedding model服务和火山引擎的deepseek API构建本地知识库
  • 世界高血压日|专家:高血压患者控制血压同时应注重心率管理
  • 第十届曹禺剧本奖上海揭晓,首次开放个人申报渠道
  • 61岁云浮市律师协会副会长谭炳光因突发疾病逝世
  • 魔都眼|锦江乐园摩天轮“换代”开拆,新摩天轮暂定118米
  • 1至4月全国铁路发送旅客14.6亿人次,创同期历史新高
  • 习近平复信中国丹麦商会负责人