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

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容器除了这些之外,还有其他的用法,可以在实践的过程中逐渐摸索,及时记录,便于之后的工作。

原文地址:https://blog.csdn.net/2503_91044785/article/details/146323083
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/589600.html

相关文章:

  • Spring Boot 动态配置管理:ZooKeeper 集成与 Redis 配置覆盖实践
  • easypoi导入Excel兼容日期和字符串格式的日期和时间
  • OpenCV计算摄影学(23)艺术化风格化处理函数stylization()
  • 【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 的自动配置:约定优于配置的设计美学
  • Vue 登录 记住密码,设置存储时间
  • ROS学习过程记录(二)
  • Spark 优化作业性能以及处理数据倾斜问题
  • 天梯赛 L2-002 链表去重
  • 深度学习在医学影像分析中的应用:DeepSeek系统的实践与探索
  • SwanLab邮件通知插件:训练完成收到邮件,掌握训练进度更及时
  • 全栈网络安全-渗透测试-2
  • Linux 脚本Shell 的应用场景
  • 莱姆森科技携手东莞市农林水务局助力乡村振兴 佛顶山村食堂建设项目圆满竣工
  • 计算机网络笔记再战——理解几个经典的协议HTTP章3
  • java多线程基础
  • Ubuntu零基础学习---基础指令
  • 依赖倒置 DIP、依赖注入 DI、控制反转 IoC 和工厂模式
  • Kotlin-inline函数特效
  • 【从0到1搞懂大模型】RNN基础(4)
  • Spring组件初始化扩展点:BeanPostProcessor