std::set和std::map底层均基于红黑树,性能相同;区别仅在于set存储单一元素(键即值),map存储键值对;选择依据是是否需要键值分离。

set 和 map 的底层实现完全一样
它们都基于红黑树(std::set 和 std::map 默认都是 std::less 比较 + 红黑树),插入、查找、删除都是 O(log n),内存布局和迭代器行为也一致。区别只在「存什么」和「怎么查」。
常见误解是“set 慢一点”,其实只要不滥用 operator[] 或 at(),两者性能几乎无差别。
用 set 还是 map?看你要不要「键值分离」
std::set 存的是单一元素,这个元素既是键也是值;std::map 存的是键值对,键用于排序和查找,值用于存储附加信息。
- 要判断某个整数是否出现过 → 用
std::set - 要查“学号 → 姓名”映射 → 用
std::map - 要按字符串长度排序,但只存字符串本身 → 不能直接用
set,得自定义比较器:std::set<:string decltype auto a const b return a.size b.size>
insert / find / erase 的参数和返回值差异很关键
set::insert 接收单个 T,返回 std::pair;map::insert 接收 std::pair 或 std::initializer_list,返回类型相同但语义不同:bool 表示「键是否新增」而非「元素是否新增」。
立即学习“C++免费学习笔记(深入)”;
map::find 返回 iterator 到键值对,解引用后是 std::pair;set::find 返回 iterator 到元素本身。
容易踩的坑:
- 误用
map[key] = value触发默认构造(如果Value不可默认构造会编译失败) - 用
map.find(key) != map.end()判断存在性是对的,但用map[key]再判断是否为默认值是错的——它已悄悄插入 -
set没有operator[],写s[0]直接编译失败
multiset / multimap 是唯一需要认真考虑的分支
当允许重复键时,std::multiset 和 std::multimap 才有意义。它们不提供 operator[],且 find() 只返回一个迭代器(哪怕有多个匹配),必须用 equal_range() 遍历全部。
注意:multimap 的键依然不可修改(因为要维持红黑树结构),所以 iter->first 是 const,但 iter->second 可改。
如果你只是想“按 key 分组存多个 value”,有时用 std::map 更直观、更易读,尤其当 value 数量少且增删不频繁时。
真正需要 multimap 的典型场景是:频繁按 key 查找 + 同时需要按插入顺序或值大小做范围遍历 —— 这时候红黑树的天然有序性才有不可替代的优势。










