map | unordered_map | set | unordered_set基础用法解析

STL关联容器基础用法解析

map | unordered_map | set | unordered_set是四类重要的关联容器,它们是构建高效数据结构和算法的基石,常用于通过键 (key) 来快速查找、插入和删除数据。

一、认识四大关联容器

有序 (基于红黑树, O(log N))无序 (基于哈希表, O(1)平均)
键值对 (字典)std::mapstd::unordered_map
仅键 (集合)std::setstd::unordered_set

1. std::map - 自动排序的字典

  • 比喻:一本永远按首字母排好序的字典。
  • 头文件#include <map>
  • 核心:存储唯一的、根据键自动升序排序的键值对。

2. std::set - 自动排序的唯一集合

  • 比喻:一份不允许重名且自动按字母顺序排好队的嘉宾名单。
  • 头文件#include <set>
  • 核心:存储唯一的、自动升序排序的元素。

3. std::unordered_map - 高性能的杂乱字典

  • 比喻:一本查找速度极快,但内容杂乱无章的字典。
  • 头文件#include <unordered_map>
  • 核心:存储唯一的、无序的键值对,平均查找速度最快。

4. std::unordered_set - 高性能的杂乱集合

  • 比喻:一份登记速度极快,但名单顺序杂乱的嘉宾列表。
  • 头文件#include <unordered_set>
  • 核心:存储唯一的、无序的元素,平均查找速度最快。

二、增删查改遍历

对于C++初学者,不必学习每个函数的细枝,深究其内部实现,学会增删查遍历改足以。

对于 std::mapstd::unordered_map

  • 插入/修改: 熟练使用 my_map[key] = value;
  • 查找: 必须掌握 find()! if (my_map.find(key) != my_map.end()) 是判断键是否存在的标准做法
  • 删除: 熟练使用 my_map.erase(key);
  • 遍历: 熟练使用 for (const auto& pair : my_map),并知道 pair.first 是键,pair.second 是值。

对于 std::setstd::unordered_set

  • 插入: 熟练使用 my_set.insert(value);
  • 查找: 熟练使用 count() 判断存在性,if (my_set.count(value)) 更简洁。
  • 删除: 熟练使用 my_set.erase(value);
  • 遍历: 熟练使用 for (const auto& value : my_set)

三、组合容器

学习容器的最终目的是解决实际问题,而这通常需要将它们组合起来。

核心用法:map 存储 vector

map 的键用来索引,vector 作为值用来存储一组数据。

案例:记录每个学生的多门考试成绩

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

int main() {
    // 键是学生姓名 (string),值是该学生的所有成绩 (vector<int>)
    std::map<std::string, std::vector<int>> student_grades;

    // --- 为张三添加成绩 ---
    // 1. 直接用 [] 访问 "Zhang San"。因为他不存在,map 会自动创建一个键 "Zhang San"
    //    和一个与之关联的空 vector。
    // 2. 然后对这个 vector 调用 push_back() 添加成绩。
    student_grades["Zhang San"].push_back(95);
    student_grades["Zhang San"].push_back(88);
    student_grades["Zhang San"].push_back(92);

    // --- 为李四添加成绩 ---
    student_grades["Li Si"].push_back(100);
    student_grades["Li Si"].push_back(76);

    // --- 遍历并打印所有学生的成绩 ---
    std::cout << "所有学生的成绩单:" << std::endl;
    for (const auto& pair : student_grades) {
        std::cout << "学生: " << pair.first << "  成绩: ";
        // pair.second 就是那个 vector
        for (int grade : pair.second) {
            std::cout << grade << " ";
        }
        std::cout << std::endl;
    }
}

输出:
所有学生的成绩单:
学生: Li Si 成绩: 100 76
学生: Zhang San 成绩: 95 88 92

核心技巧my_map[key] 会返回与 key 关联的那个 vector引用。所以可以直接在其后调用 vector 的成员函数,如 .push_back(),代码非常简洁。

初学者陷阱:set 存储 vector

是否可以 std::set<std::vector<int>> 来存储一组不重复的 vector 呢?

答案是:理论上可以,但实践中很复杂,初学者应避免。

set 需要对内部元素进行排序,但 C++ 默认不知道如何比较两个 vector 的“大小”。直接使用会导致编译错误。虽然可以通过自定义比较器解决,但这是一个高级话题。

建议setunordered_set 主要用来存储 int, double, std::string 等基础类型。不要轻易尝试将 vectormap 等复杂容器作为它们的元素。

总结与决策指南

  1. 需要存键值对吗?

    • -> mapunordered_map
    • -> setunordered_set
  2. 需要数据根据键自动排序吗?

    • -> mapset
    • 否,只想要最快的查找速度 -> unordered_mapunordered_set

最重要的经验法则:如果不确定,并且不强制要求排序,请优先选择 unordered 版本,因为它们通常更快,性能更好。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值