c++中set和map的区别_c++关联容器选择指南【对比】

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

set 和 map 的底层实现完全一样

它们都基于红黑树(std::setstd::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::pairmap::insert 接收 std::pairstd::initializer_list,返回类型相同但语义不同:bool 表示「键是否新增」而非「元素是否新增」。

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::multisetstd::multimap 才有意义。它们不提供 operator[],且 find() 只返回一个迭代器(哪怕有多个匹配),必须用 equal_range() 遍历全部。

注意:multimap 的键依然不可修改(因为要维持红黑树结构),所以 iter->first 是 const,但 iter-

>second 可改。

如果你只是想“按 key 分组存多个 value”,有时用 std::map> 更直观、更易读,尤其当 value 数量少且增删不频繁时。

真正需要 multimap 的典型场景是:频繁按 key 查找 + 同时需要按插入顺序或值大小做范围遍历 —— 这时候红黑树的天然有序性才有不可替代的优势。