std::set、std::map 和 std::unordered_map

在 C++ 标准库中,std::setstd::mapstd::unordered_map 是常用的关联容器,但它们在实现方式、性能和应用场景上有显著差异。以下是它们的核心区别:


1. 数据结构与有序性

  • std::set / std::map
    基于 红黑树(Red-Black Tree) 实现,元素(或键值对)严格有序(按升序排列)。

    • std::set:存储唯一键值,仅键可被访问。
    • std::map:存储键值对,键唯一,通过键快速查找值。
  • std::unordered_map
    基于 哈希表(Hash Table) 实现,元素无序。键唯一,通过哈希函数快速定位值。


2. 时间复杂度

操作std::set/std::mapstd::unordered_map
插入O(log n)平均 O(1),最坏 O(n)
删除O(log n)平均 O(1),最坏 O(n)
查找O(log n)平均 O(1),最坏 O(n)
范围查询(如 lower_boundO(log n + k)(k为结果数量)不支持有序范围查询

3. 内存占用

  • 红黑树set/map
    内存占用相对较高,但结构紧凑,节点存储父节点、子节点指针和颜色标记。

  • 哈希表unordered_map
    需要额外空间处理哈希冲突(如负载因子控制),通常内存占用更高,但实际访问速度更快。


4. 迭代器稳定性

  • std::set/std::map
    插入或删除元素时,只有被操作的节点的迭代器失效,其他迭代器不受影响。

  • std::unordered_map
    插入可能导致哈希表 重新哈希(如扩容),此时所有迭代器都会失效。


5. 允许重复键?

  • 所有容器均不允许重复键。若插入重复键:
    • std::set/map:插入失败,返回 false
    • std::unordered_map:覆盖旧值(可通过检查返回的 std::pair<bool, T&> 判断是否已存在)。

6. 应用场景

  • std::set
    需要唯一元素的有序集合,支持快速插入、删除和范围查询(如日期排序、唯一用户ID管理)。

  • std::map
    需要键值对的有序映射,如配置项存储(键为字符串,值为整数)。

  • std::unordered_map
    需要高速哈希查找的场景,如缓存系统、字典(键值对频繁访问且无需顺序)。


示例代码对比

#include <iostream>
#include <set>
#include <map>
#include <unordered_map>

int main() {
    std::set<int> s = {3, 1, 4};
    std::map<std::string, int> m = {{"a", 1}, {"b", 2}};
    std::unordered_map<std::string, int> um = {{"x", 10}, {"y", 20}};

    // set 和 map 是有序的
    for (auto num : s) std::cout << num << " "; // 输出 1 3 4
    for (auto& kv : m) std::cout << kv.first << ": " << kv.second << " "; // a:1 b:2

    // unordered_map 无序
    for (auto& kv : um) std::cout << kv.first << ": " << kv.second << " "; 
    // 可能输出 x:y 或 y:x 等不确定顺序

    return 0;
}

总结

  • 有序、稳定、范围查询 → 选 setmap
  • 快速哈希查找 → 选 unordered_map
  • 内存敏感且数据量小 → 优先 set/map;大数据量且追求速度 → 选 unordered_map
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值