核心概念: 这些容器都是关联容器。它们的特点是其中的元素是按照特定的排序准则(通常是 < 运算符或者自定义的比较函数)进行排序的。这种排序使得查找、插入和删除操作非常高效,时间复杂度通常为 $O(\log n)$。它们的底层实现通常是红黑树


1. setmultiset

  • 存储内容: 存储唯一的 (key)。set 中的键是唯一的,multiset 中的键可以重复。

  • 定义:

    #include <set>
    std::set<Key, Compare = std::less<Key>, Allocator = std::allocator<Key>> set_name;
    std::multiset<Key, Compare = std::less<Key>, Allocator = std::allocator<Key>> multiset_name;
    

    • Key: 容器中存储的元素类型。这个类型必须支持比较操作(通过 < 运算符或自定义的 Compare)。
    • Compare: 比较函数对象的类型,用于定义排序规则。默认是 std::less<Key>,即升序排列。可以自定义,例如 std::greater<Key> 实现降序。
    • Allocator: 内存分配器类型,通常使用默认值。
  • 主要特性:

    • 排序: 元素始终按 Compare 定义的规则保持有序。
    • 唯一性 (仅 set): set 中不允许两个元素具有相同的值(根据 Compare 判断相等)。
    • 键即值:setmultiset 中,key 就是存储的值本身 (value_type 就是 Key)。
    • 迭代器: 提供双向迭代器 (iterator, const_iterator)。迭代器按排序顺序遍历元素。修改元素的值(通过迭代器)可能破坏容器的排序,因此是不允许的。 只能插入新元素或删除现有元素。
  • 关键成员函数:

    • 插入:
      std::pair<iterator, bool> insert(const Key& key); // set: 插入成功返回 {iterator, true}, 失败(重复)返回 {iterator, false}
      iterator insert(const Key& key);                  // multiset: 总是成功,返回新元素迭代器
      iterator insert(iterator hint, const Key& key);   // 使用提示位置尝试优化插入
      void insert(InputIterator first, InputIterator last); // 插入一个范围内的元素
      
    • 查找:
      iterator find(const Key& key);         // 查找等于 key 的元素,找到返回迭代器,否则返回 end()
      const_iterator find(const Key& key) const;
      size_type count(const Key& key) const; // 返回等于 key 的元素个数 (set 为 0 或 1, multiset 可能 >1)
      

    • 范围查询 (基于排序):
      iterator lower_bound(const Key& key); // 返回第一个不小于 key 的元素的迭代器
      iterator upper_bound(const Key& key); // 返回第一个大于 key 的元素的迭代器
      std::pair<iterator, iterator> equal_range(const Key& key); // 返回包含所有等于 key 的元素的范围 [lower_bound, upper_bound)
      

      • 这些操作对于 multiset 查找重复键的所有元素非常有用。
    • 删除:
      size_type erase(const Key& key); // 删除所有等于 key 的元素,返回删除的个数
      iterator erase(iterator position); // 删除迭代器 position 指向的元素
      iterator erase(iterator first, iterator last); // 删除范围 [first, last) 内的元素
      

    • 大小和容量:
      bool empty() const;
      size_type size() const;
      size_type max_size() const;
      
    • 其他:
      void clear(); // 清空容器
      key_compare key_comp() const; // 返回比较函数对象的副本
      value_compare value_comp() const; // 对于 set/multiset, value_compare 等同于 key_compare
      


2. mapmultimap

  • 存储内容: 存储由 (key) 和 (value) 组成的键值对 (pair<const Key, Value>)。map 中的键是唯一的,multimap 中的键可以重复。

  • 定义:

    #include <map>
    std::map<Key, Value, Compare = std::less<Key>, Allocator = std::allocator<std::pair<const Key, Value>>> map_name;
    std::multimap<Key, Value, Compare = std::less<Key>, Allocator = std::allocator<std::pair<const Key, Value>>> multimap_name;
    

    • Key: 键的类型。必须支持比较操作。
    • Value: 与键关联的值的类型。
    • Compare: 比较键的函数对象的类型,用于定义排序规则。默认是 std::less<Key>
    • Allocator: 内存分配器类型,通常使用默认值。
  • 主要特性:

    • 排序: 元素(键值对)始终按照键 (Key),根据 Compare 定义的规则保持有序。
    • 唯一性 (仅 map): map 中不允许两个元素具有相同的键(根据 Compare 判断相等)。
    • 键值对: 元素类型是 std::pair<const Key, Value>。键 (Key) 是 const 类型,不能修改(修改会破坏排序)。值 (Value) 可以通过迭代器或特定接口修改。
    • 迭代器: 提供双向迭代器 (iterator, const_iterator)。迭代器按键的排序顺序遍历元素。通过迭代器可以修改 value (it->second = new_value;),但不能修改 key (it->firstconst)。
  • 关键成员函数 (大部分与 set/multiset 类似):

    • 插入:
      std::pair<iterator, bool> insert(const value_type& kv_pair); // map: 插入成功返回 {iterator, true}, 失败(重复键)返回 {iterator, false}
      iterator insert(const value_type& kv_pair);                  // multimap: 总是成功,返回新元素迭代器
      iterator insert(iterator hint, const value_type& kv_pair);   // 使用提示位置
      void insert(InputIterator first, InputIterator last);        // 插入一个范围内的键值对
      

      • value_typestd::pair<const Key, Value>。通常使用 std::make_pair(key, value){key, value} (C++11 起) 创建。
    • 访问/修改元素 (map 特有):
      Value& operator[](const Key& key); // 1. 如果 key 存在,返回其 value 的引用。
                                        // 2. 如果 key 不存在,则插入一个具有该 key 的默认构造的 Value,并返回其引用。
      Value& at(const Key& key);         // 访问指定 key 的 value 的引用,若 key 不存在则抛出 std::out_of_range 异常。
      const Value& at(const Key& key) const;
      

      • operator[] 提供了一种便捷但可能插入新元素的方式。at() 提供了边界检查的安全访问。
      • multimap 没有 operator[],因为一个键可能对应多个值。
    • 查找:
      iterator find(const Key& key);         // 查找键等于 key 的元素,找到返回迭代器,否则返回 end()
      const_iterator find(const Key& key) const;
      size_type count(const Key& key) const; // 返回键等于 key 的元素个数 (map 为 0 或 1, multimap 可能 >1)
      

    • 范围查询 (基于键排序):
      iterator lower_bound(const Key& key); // 返回第一个键不小于 key 的元素的迭代器
      iterator upper_bound(const Key& key); // 返回第一个键大于 key 的元素的迭代器
      std::pair<iterator, iterator> equal_range(const Key& key); // 返回包含所有键等于 key 的元素的范围 [lower_bound, upper_bound)
      

      • 这些操作对于 multimap 查找同一键对应的所有值非常有用。
    • 删除、大小、容量、比较函数等:set/multiset 中的对应函数功能和使用方式基本相同,只是操作的对象是键值对。

总结与对比

特性setmultisetmapmultimap
存储内容唯一键 (Key)可重复键 (Key)唯一键值对 (pair<const Key, Value>)可重复键值对 (pair<const Key, Value>)
元素唯一性键唯一键可重复键唯一键可重复
底层结构红黑树 (通常)红黑树 (通常)红黑树 (通常)红黑树 (通常)
排序依据Key (按 Compare)Key (按 Compare)Key (按 Compare)Key (按 Compare)
时间复杂度查找、插入、删除: $O(\log n)$查找、插入、删除: $O(\log n)$查找、插入、删除: $O(\log n)$查找、插入、删除: $O(\log n)$
迭代器修改不能修改元素 (会破坏排序)不能修改元素 (会破坏排序)不能修改 key (const), 可以修改 value不能修改 key (const), 可以修改 value
直接访问值N/A (键即值)N/A (键即值)operator[], at() (仅 map)operator[]
主要用途有序唯一元素集合有序元素集合 (允许重复)字典、关联数组 (键唯一映射到值)一对多映射 (一个键对应多个值)

选择指南:

  • 需要存储唯一值并按值排序:用 set
  • 需要存储可能重复的值并按值排序:用 multiset
  • 需要建立唯一键到值的映射,并按键排序:用 map。可以通过键快速查找或修改对应的值。
  • 需要一个键对应多个值,并按键排序:用 multimap。使用 equal_range 或遍历来获取同一键的所有值。

这些关联容器是 C++ STL 中非常强大和常用的工具,理解它们的特性和区别对于编写高效、正确的代码至关重要。

更多推荐