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