构造函数

  1. 默认构造

    • 序列容器:✔
    • 关联容器:✔
    • 哈希容器:✔
    • 容器适配器:✔
  2. 初始化列表

    • 序列容器:✔

      deque<int>dq({ 1, 2, 3 })
      deque<double> dq = {3.14, 2.71, 1.618};
      
      string s3("hello"); 
      string s5 = "world";
      
    • 关联容器:✔

      map<string, int> m3 = {{"a",1}, {"b",2}};
      map<int, string> mymap ({ { 1, "hello" }, {2, "world"} });
      
    • 哈希容器:✔

    • 容器适配器:×

  3. 移动构造

    • 序列容器:✔,除了 array

      string str1 = "Hello";
      string str2 = move(str1); 
      
    • 关联容器:✔

    • 哈希容器:✔

    • 容器适配器:✔

      源对象的所有迭代器、引用、指针失效

      deque<int> dq = { 5, 6, 7 };
      stack<int> s3(move(dq));
      

      priority_queue 使用已有容器移动构造,要加上比较器

      auto comp = [](int a, int b) { 
          return a > b;
      };
      vector<int> vec2 = { 7, 1, 9, 4 };
      priority_queue<int, vector<int>, decltype(comp)>
          pq6(comp, move(vec2));
      
  4. 范围构造,拷贝构造,operator=

    • 序列容器:✔, array没有范围构造

      forward_list<int> l3 = { 9, 7, 5, 3, 1 };
      forward_list<int> l4(l3.begin(), l3.end());
      
      // l4 = { 9, 7, 5, 3, 1 }
      // 区间左闭右开
      // 区别于 splice_after 与 erase_after 
      
    • 关联容器:✔

      vector<int> vec = {3,1,2,2};
      set<int> s3(vec.begin(), vec.end());
      
      int arr[] = {1,2,3};
      set<int> v5(arr, arr+3);
      // arr + 2 会截断 
      
    • 哈希容器:✔

    • 容器适配器:✔,stack 和 queue 不支持范围构造

      priority_queue<int, vector<int>, greater<int>> 
          pq4(vec.begin(), vec.end(), greater<int>());
      // greater<int>() 可写可不写
      

      拷贝底层容器,不能拷贝其他容器

      deque<int> dq = { 5, 6, 7 };
      stack<int> s3(dq);
      

      priority_queue 要加上比较器

      auto comp = [](int a, int b) { 
          return a > b;
      }
      priority_queue<int, vector<int>, decltype(comp)>
          pq5(comp, vec);
      
  5. count 个 value

    • 序列容器:✔,除了array

      初始化 n 个值为 val 的元素
      val 默认值为 T()

      vector<int> v2(5);
      // 5个int(默认0)
      
      string s2(5, 'a'); 
      
    • 关联容器:×

    • 哈希容器:×

  6. 自定义比较器(函数对象)

    • 序列容器:×

    • 关联容器:✔

      • multimap 的比较器
        只比较键,不比较值
      map<int, string, greater<int>> map6;
      
    • 哈希容器:✔

      • unordered_multimap 的相等性比较器
        只比较键,不比较值
      unordered_set<int> set4(50); // 初始桶数=50
      
      unordered_set<int, MyHash> set5(10, MyHash{});
      
      unordered_set<int, MyHash, MyEqual>
          set6(5, MyHash{}, MyEqual{});
      // 函数参数列表 可写可不写
      
    • 容器适配器:✔,仅限 priority_queue

      priority_queue<int, vector<int>, greater<int>> pq;
      // 最小堆
      
  7. 自定义比较器(lambda)

    • 序列容器:×

    • 关联容器:✔

    • 哈希容器:✔

      auto strHash = [](const string& s) {
          return s.size();
      };
      unordered_map<string, int, decltype(strHash)>
          map5(10, strHash);
      
      auto strEqual = [](const string& a, const string& b) { 
          return a[0] == b[0]; // 首字母相同即相等
      };
      unordered_map<string, int, decltype(strHash), decltype(strEqual)> 
          map6(5, strHash, strEqual);
      
    • 容器适配器:✔,仅限 priority_queue

  8. 自定义比较器(函数指针)

    • 序列容器:×

    • 关联容器:✔

      bool comp(int a, int b) {
      	return a > b;
      }
      map<int, string, bool(*)(int, int)> map1(comp);
      
      bool(*p)(int, int) = [](int a, int b) {
          return a > b;
      };
      map<int, string, decltype(p)> map7(p, {
          {3, "three"}, {1, "one"}, {4, "four"}
      });
      
    • 哈希容器:✔

    • 容器适配器:✔,仅限 priority_queue

  9. 指定底层容器

    • 序列容器:×

    • 关联容器:×

    • 哈希容器:×

    • 容器适配器:✔

      选择底层容器只考虑 vector, list, deque

      1. stack
        在容器尾部 插入 删除

      2. queue
        在容器头部 删除(排除 vector )
        在容器尾部 插入

      3. priority_queue
        随机访问迭代器(排除 list )
        在容器尾部 插入 删除

      以下容器不作为底层容器

      • array(大小固定)
      • string(类型限制)
      • forward_list (无法对尾部操作)
      • 关联容器,哈希容器(无 front 和 back)
      stack<int, vector<int>>s2;
      
      queue<int, list<int>> q;
      

  10. 其他的构造函数

    string s3("hello");
    string s4(s3, 1, 3);
    // 从s3的索引1开始,取3个字符 → "ell"
    

    image

迭代器

  1. begin, end, std::next(it, n), n 为正数, ++it

    • 序列容器:✔
    • 关联容器:✔
    • 哈希容器:✔
      • 任意位置的迭代器
        哈希表的桶遍历

    next 通过 ++it 执行 n 次自增(默认 n=1 )

  2. rbegin, rend, std::next(it, n), n 为负数, --it

    • 序列容器:✔,forward_list 除外

      • rbegin 和 rend 是反向迭代器
        容器必须提供双向迭代器
        或随机访问迭代器

      • forward_list:单向链表
        只支持前向迭代器

    • 关联容器:✔,逆序遍历O(n)

    • 哈希容器:×

      • 前向迭代器
        只能 ++ 不能 --
        不支持反向遍历
  3. cbegin, cend

    • 序列容器:✔
    • 关联容器:✔
    • 哈希容器:✔
  4. before_begin

    • 序列容器:✔,仅限 forward_list

      • 返回指向链表第一个元素之前位置的迭代器
        用于在头部插入

        • 单向链表无法从当前节点访问前驱节点
          只能插入指定节点的后方

        • 不能解引用

      • list 双向链表
        通过 begin 即可插入
        无需首前迭代器

    • 关联容器:×

    • 哈希容器:×

    std::forward_list<int> list = {2, 3, 4};
    list.insert_after(list.before_begin(), 1);
    // 结果: 1 2 3 4
    
  5. operator+, operator-

    • 序列容器:✔

      • list, forward_list 除外

      • 要求 随机访问迭代器

    • 关联容器:×

    • 哈希容器:×

元素访问

  1. 范围 for 循环

    • 序列容器:✔

    • 关联容器:✔

      • 红黑树的中序遍历(按键排序)

      • 稳定
        对于相同键的元素
        先插入的元素在前

    • 哈希容器:✔

    时间复杂度都是 O(n)
    但常数因子不同
    image

    迭代器模式的语法糖

    map<string, int> scores = {{"Alice", 90}, {"Bob", 85}};
    for (const auto& pair : scores) {
        cout << pair.first << ": " << pair.second << "\n";
    }
    
    vector<int> vec = {10, 20, 30};
    for (auto& element : vec) {
        element *= 2;
    } // 直接引用元素,可修改原始数据
    
  2. operator[], at

    • 序列容器:✔, O(1)

      • list 和 forward_list 除外

      • 随机访问

      • 都返回引用

    • 关联容器:✔,O(logn)

      • 仅限 map

      • multimap:允许多个相同键
        无法确定返回哪个值

      • 更新已存在的键

        • operator[],存在则覆盖/更新
        • insert:存在则插入失败
      • 访问已存在的键
        返回对应值的引用

      • 访问不存在的键

        • operator[]
          自动插入一个默认值
          (如 int 为 0,string 为空字符串)
          并返回其引用
          迭代器有效

        • at
          不插入新元素
          键不存在则抛异常

    • 哈希容器:✔,O(1)

      • 仅限 unordered_map

      • 都返回引用

      • 可能使所有迭代器失效
        (当触发重新哈希时)

    string str = "hello";
    char& c = str[1];
    c = 'a';
    // str 为 aello
    
    map<string, int> scores;
    scores["Alice"] = 90;  // 插入键值对
    int alice_score = scores["Alice"];
    int bob_score = scores["Bob"];  
    // 插入 {"Bob", 0} 并返回 0
    
    map<string, int> scores;
    try {
        cout << scores.at("Bob") << endl;
    }
    catch(const out_of_range& e){
        cerr << e.what() << endl;
    } // invalid map<K, T> key
    
  3. data

    • 序列容器:✔,O(1)

      • list, forward_list, deque 除外

      • 连续存储的容器支持
        返回指向底层数组的指针

      • 链表类容器不支持
        因为元素非连续存储

      • deque 非连续内存结构
        由多个固定大小的块(通常是数组)组成
        元素分散存储在多个内存块中
        无法提供单个连续的指针访问所有元素

    • 关联容器:×

    • 哈希容器:×

    vector<int> vec = {1, 2, 3, 4, 5};
    int* ptr = vec.data();
    ptr[2] = 100;
    for (size_t i = 0; i < vec.size(); ++i) {
        cout << ptr[i] << " ";  // 输出: 1 2 100 4 5
    }
    
    string str = "hello";
    const char* ptr = str.data();
    cout << ptr;
    // 输出:hello
    
  4. front, back

    • 序列容器:✔,O(1)

      • forward_list 无 back
        存储尾指针 或 O(n) 都不理想
    forward_list<string> fl = {"hello", "world"};
    fl.front() = "Hi";
    // 修改第一个元素
    

    string 的 back() 不是返回\0

    string str = "hello";
    str.back() = '!';  // 修改最后一个字符
    cout << str;  // 输出: hell!
    
    • 关联容器:×

      • 基于红黑树实现
        不保证元素在内存中连续存储
        没有明确的"第一个"或"最后一个"物理位置
    • 哈希容器:×

      • 基于哈希表实现
        元素无固定顺序
        访问首尾元素没有意义
    • 容器适配器:✔, O(1)

      • 仅限 queue

      • stack 和 priority_queue

        • 没有 front 和 back,但有 top

        • 栈的 top() 调用底层容器的 back()

        • 优先队列的 top() 调用底层容器的 front()

      int& top1 = stack1.top();
      top1 = 114514;
      
  5. operator*(不是乘法,是迭代器解引用)

    • 序列容器:✔

      • 返回元素的 非 const 引用
      auto it = vec.begin();
      *it = 10;
      
    • 关联容器:✔

      • 返回 const 键引用 + 非 const 值引用
      • 键是 const 保证有序性
      auto it = map1.begin();
      it->second = "A";
      
    • 哈希容器:✔

      • 返回 const 键引用 + 非 const 值引用

      • 禁止修改键
        否则会导致哈希值变化
        破坏元素在表中的位置

容量

  1. size

    • 序列容器:✔,
      • forward_list(c++11)无 size
    • 关联容器:✔
    • 哈希容器:✔
    • 容器适配器:✔

    都是 O(1)

  2. empty

    • 序列容器:✔
    • 关联容器:✔
    • 哈希容器:✔
    • 容器适配器:✔

    都是 O(1)

  3. max_size

    • 序列容器:✔
    • 关联容器:✔
    • 哈希容器:✔

    array的 max_size() 等同于 size()
    其他容器的 max_size() 无意义

  4. capacity

    • 序列容器:✔,O(1)

      • 仅限 vector 和 string

      • array:固定大小,size() 即容量

      • list, forward_list

        • 元素存储在独立的节点
          每个节点的内存是独立分配

        • 插入新元素时
          仅需分配一个新节点
          无需预先分配内存空间

        • capacity() 的前提
          当前已分配内存空间

      • deque 由多个连续的内存块组成
        每个内存块有自己的容量
        但 deque 整体没有一个统一的 “容量” 概念

    • 关联容器:×

    • 哈希容器:×

      • bucket_count() 返回桶的数量
      • load_factor() 返回平均每个桶的元素数

    size():当前实际存储的元素数量
    capacity():当前已分配的内存最多能存储的元素数量

    当元素数量超过 capacity() 时
    vector 和 string 会自动重新分配更大的内存空间
    并将原有元素复制到新空间中

    string str6 = "ab";
    size_t n = str6.capacity();
    // n 为 15
    
    string num = "123456789012345";
    cout << num.capacity();
    // 结果:15
    // 内部可能以 '\0' 结尾,但 capacity() 不包含该字符
    
  5. assign

    • 序列容器:✔

      • O(n + m),由 clear 与 insert 的时间复杂度相加得到

      • array 除外
        清空容器相当于 clear
        array 不支持 clear

      • 清空 所有原有元素

        • 相当于 clear,size 变为0

        • capacity 不变

        • assign 和 clear 在迭代器失效上完全一致
          调用后所有迭代器、指针和引用立即失效

      • 插入 新元素

        • 如果新元素数量 ≤ 当前 capacity
          capacity 不变

        • 跟这些 构造函数 参数相同,返回值相同
          范围构造,初始化列表,count 个 val

        • 跟 序列容器 insert 多个元素有点像
          参数列表中的iterator没有
          返回值由 全是iterator 变成 全是void

    • 关联容器:×

      • 树的析构 O(n)
        树的建立 O(nlogn)
    • 哈希容器:×

      • 为了查找、插入和删除
        而非批量替换

    string 的 assign 返回值 全是 string

    vector<int> src = { 1, 2, 3, 4 };
    deque<int> des;
    des.assign(src.begin(), src.end());
    // 从 vector 复制元素到 deque
    
    forward_list<int>l1;
    forward_list<int>l2 = { 1, 2, 3, 4, 5 };
    l1.assign(l2.begin(), l2.end());
    
    // l1 = { 1, 2, 3, 4, 5 }
    // 区间:左闭右开
    // 区别于 splice_after 与 erase_after
    
    vector<int> vec;
    vec.assign(5, 10);
    // 将5个值为10的元素赋给vec
    vec.assign({1, 2});
    // 用初始化列表赋值
    

    string 还支持以下三种重载函数

    string& assign(const string& str);
    
    string& assign(const string& str, size_t pos, size_t len);
    
    string& assign(const char* s, size_t n);
    
  6. resize

    • 序列容器:✔,array 除外

      • resize 调整 size

      • vector, string

        • O(n + k):若触发内存重新分配

        • O(k):若无需重新分配
          仅插入 / 删除

      • list, deque:O(k)

      • forward_list:O(n + k)

        • 需遍历到尾部
    • 关联容器:×

    • 哈希容器:×

    返回值都是 void

    vector<int> vec = {1, 2, 3};
    vec.resize(5);     
    // 新增元素默认初始化为0
    // {1, 2, 3, 0, 0}
    
    vec.resize(7, 42);
    // 新增元素初始化为42
    // {1, 2, 3, 0, 0, 42, 42}
    
    vec.resize(2);
    // {1, 2}
    
  7. reserve

    • 序列容器:✔,仅限 vector 和 string

      • 理由参考 capacity

      • reserve(n) 预分配至少能容纳 n 个元素的内存空间

      • O(1):n ≤ 当前 capacity

        • 无需重新分配内存

        • 迭代器,指针,引用 都不失效

      • O(m):n > 当前 capacity

        • 新内存分配:O(1)

        • 将原有的 m = size() 个元素复制到新空间

        • 内存释放:O(1)

    • 关联容器:×

    • 哈希容器:✔

      • reserve(n) 预分配至少能容纳 n 个元素的桶数组

        bucket_count >= ceil(n / max_load_factor())
        // 新分配的桶的数量:质数
        
      • O(1):满足以上条件
        内存,引用都有效

      • O(m + b):不满足以上条件
        当前桶数不足,需扩容

        • 分配新桶
          b = 新分配的桶数

        • 重哈希
          m = 当前元素数量 size()

      • 后续插入元素时
        只要元素数不超过 n
        保证不会重哈希
        适用于批量插入大量元素

    container.reserve(n);
    // 返回类型 void
    
  8. shrink_to_fit

    • 序列容器:✔,O(n)

      • array, forward_list, list 除外

      • vector, string
        请求容器将 capacity() 减少至 size()
        释放多余内存

      • deque
        请求释放未使用的内存块

      • 迭代器、指针,引用 全部失效
        内存重新分配
        不同于 reserve

    • 关联容器:×

    • 哈希容器:×

    container.shrink_to_fit();
    // 返回类型 void
    

修改

  1. clear

    • 序列容器:✔,O(n)

      • array 除外,大小固定

      • vector, string
        调用元素的析构函数
        对于基本类型则直接清除值
        但不释放内存
        保留capacity

      • deque
        释放所有内存块

      • list, forward_list
        释放所有节点内存

    • 关联容器:✔,O(n)

      • 释放所有节点内存
    • 哈希容器:✔,O(n)

      • 调用元素的析构函数
        但保留 bucket 数组
        不释放内存
    • 容器适配器:×(c++11)

    所有迭代器、引用和指针均失效
    链表容器 + 关联容器 + 哈希容器的 end() 仍然有效

    //容器大小变为0
    container.clear();
    
  2. swap

    • 序列容器:✔

      • 交换内部指针或大小
        不涉及元素的复制或移动
    • 关联容器:✔

      • 交换底层树结构的根指针
    • 哈希容器:✔

      • 交换 桶数组指针,哈希函数,比较器
        bucket_count, size, load_factor
    • 容器适配器:✔

      • 交换底层容器

    两容器适配器/两容器 的模板参数列表要完全相同

    交换后,原容器的迭代器、引用和指针
    指向新容器的元素
    即交换前后, it 不变,ref 不变

    • array 除外,迭代器仍指向原元素
      即交换前后,it 改变,ref 改变

    • string 会失效

    //array O(n), 其他 O(1)
    container1.swap(container2);
    
  3. erase

    • 序列容器:✔

      • forward_list 和 array 除外

      • forward_list 没有 erase,但有 erase_after

      屏幕截图 2025-08-06 110000

      • erase 析构 元素
        所以两链表的erase(first, last)不是 O(1)

      • 返回的迭代器
        指向被移除元素之后的位置

      • 如果移除的是最后一个元素
        则返回 end()

      // 移除单个元素
      iterator erase(iterator pos)
      
      // 移除 [first, last)
      iterator erase(iterator first, iterator last)
      

      forward_list 的 erase_after 的两个重载函数
      形式跟上面一样
      但移除的是 pos 之后的元素
      移除 (first, last)

      string 多一个重载函数
      移除 【 str[index], str[index + count] )

      string str2 = str1.erase(index, count);
      
      string str1 = "hello,world!!!";
      string str2 = str1.erase(5, 6);
      // str2 为 hello!!!
      
    • 关联容器:✔

      • 范围插入 O(k * log(n + k))
        范围删除 O(k + logn)
        每个元素都独立删除 O(k * logn)

        • [first, last) 在树中对应
          连续的中序遍历序列

        • 为什么范围删除不是 O(k)
          不是给了迭代器吗?

      • 有两个重载函数跟序列容器一样

      • 此外还多一个重载函数

      // 返回被移除的元素数量
      size_t count = container.erase(key);
      
    • 哈希容器:✔

      • 三个重载函数都跟关联容器一样
  4. insert

    • 序列容器:✔

      • forward_list 和 array 除外

      • forward_list 没有 insert,但有 insert_after

      屏幕截图 2025-08-06 105115

      以下函数均适用

      // 这个重载函数跟 emplace 非常相似
      iterator insert(iterator pos, const T& value);
      
      iterator insert(iterator pos, size_t count, const T& value);
      
      // [first, last) ,返回的迭代器指向第一个新元素
      iterator insert(iterator pos, InputIt first, InputIt last);
      // 可以接受其他容器的迭代器,元素类型相同即可
      
      iterator insert(iterator pos, initializer_list<T> ilist);
      

      forward_list 的 insert_after 的四个重载函数
      形式跟上面一样
      在 pos 后插入元素

      与 erase_after 和 splice_after 不同
      插入的也是 [first, last)

      string 还有四个常见的重载函数

      string& insert(size_t pos, size_t count, char c);
      
      string& insert(size_t pos, const string& s);
      
      string& insert(size_t pos, const string& s,
                     size_t subpos, size_t sublen);
      // 插入 s 从位置 subpos 开始的 sublen 个字符
      
      string& insert(size_t pos, const char* s, size_t n);
      // 插入 s 的前 n 个字符
      
    • 关联容器:✔

      • 以下函数适用于 map 和 set
        因为重复插入会失败

      • multimap 和 multiset 返回类型
        不是 pair 而是 iterator
        因为一定插入成功

      // 这个重载函数跟 emplace 非常相似
      pair<iterator, bool> insert(const T& value);
      

      以下函数都适用

      //  [first, last) 
      void insert(InputIt first, InputIt last);
      
      void insert(initializer_list<T> ilist);
      
      // 这个重载函数跟 emplace_hint 非常相似
      iterator insert(iterator hint, const T& value);
      
    • 哈希容器:✔

      • 参考关联容器
    set1.insert({1, 2, 3, 4, 5});
    
    map<int, string> map1;
    map1.emplace(1, "ab");
    map1.insert({{ 1, "xy" }, { 3, "pqr" }});
    
    // map1 有 {1, "ab"} 和 {3, "pqr"}
    // 没有 {1,“xy”}
    

    string 的 insert 函数列表中的 ilist
    不接受 string,const char*
    (即不接受双引号)

    string str2 = "world";
    auto it = str2.insert(str2.begin(), {'a', 'b', 'c'});
    // str2 为 abcworld
    
  5. emplace

    • 序列容器:✔,时间复杂度同insert

      • array, string, forward_list 除外

      • forward_list 没有emplace,但有 emplace_after

      • string 不支持 emplace 系列函数

        • string 元素类型为基本字符类型
          如 char、wchar_t 等

        • emplace 系列函数适合
          容器存储复杂对象
          (如自定义类、结构体)

        • 通过转发参数给元素的构造函数
          通过传递构造函数参数
          在容器的内存空间中
          直接构造对象

        • 无需先创建临时对象
          再拷贝 / 移动到容器中

      struct Point {
        int x, y;
        Point(int a, int b) 
            : x(a), y(b) {}
      }
      
      vector<Point> vec;
      vec.emplace(vec.begin(), 1, 2);
      vec.emplace(vec.end(), 3, 4);
      // 返回值:指向新插入元素的迭代器
      

      forward_list 的 emplace_after
      形式跟上面一样
      在 pos 后就地构造

    • 关联容器:✔

      map<int, string> mp;
      auto res = mp.emplace(1, "one");
      // 返回 pair<iterator, bool>
      // multiset 和 multimap 的返回类型是 iterator
      
    • 哈希容器:✔

      • 函数与关联容器相同
    • 容器适配器:✔

      • 调用的是 底层容器的 emplace_back

      • stack 和 queue 的底层容器默认是 deque
        priority_queue 的底层容器默认是 vector

      stack<pair<int, string>> s;
      pair<int, string> p = s.emplace(3, "abc");
      // p.first 为 3
      // p.second 为 abc
      
  6. emplace_hint

    • 序列容器:×

    • 关联容器:✔,提示正确时 O(1)

      • 提示插入位置不准确
        仍能正确插入
        但无性能优化
      map<int, string> m;
      m.emplace(1, "ab"); 
      m.emplace_hint(m.end(), 2, "xy");
      
      set<int> set;
      auto it = set.begin(); // 改成 end 性能不变
      for (int i = 0; i < n_operations; ++i)
          it = set.emplace_hint(it, i);
      
      // 比 set.emplace_hint(set.end(), i) 慢
      
    • 哈希容器:✔

      • 提示的作用有限
        因元素位置由哈希值决定

  7. emplace_back

    • 序列容器:✔,O(1)

      • array, string, forward_list 除外

      • 在 c++11 中,返回类型 void

      class MyClass {
      public:
          int x;
          MyClass(int val) : x(val) {}
          MyClass(const MyClass& other) : x(other.x) {}
      };
      
      vector<MyClass> vec;
      vec.push_back(MyClass(1));// 先构造临时对象,再调用拷贝构造(或移动)
      vec.emplace_back(2);      // 直接在vector中构造,仅调用构造函数
      
    • 关联容器:×

    • 哈希容器:×

  8. push_back, pop_back

    • 序列容器:✔, O(1)

      • array, forward_list 除外

      • 在 c++11, 返回类型都为 void

      string str = "abc";
      str.push_back('d');
      // 尾部添加字符,变为"abcd"
      str.pop_back();
      
    • 关联容器:×

      • 元素按键排序
        插入位置由键值决定
        而非尾部
    • 哈希容器:×

      • 元素根据哈希值自动分配位置
  9. push_front, pop_front, emplace_front

    • 序列容器:✔,O(1)

      • array, string, vector 除外

      • string 和 vector 都是连续内存
        前端操作需要移动所有现有元素

      • 在 c++11 中,返回类型都是 void

      void pop_front();
      
      deque<int> dq = {2, 3, 4};
      dq.push_front(1);
      dq.emplace_front(0);
      // dq: {0, 1, 2, 3, 4}
      
    • 关联容器:×

    • 哈希容器:×

  10. push, pop

    • 序列容器:×
    • 关联容器:×
    • 哈希容器:×
    • 容器适配器:✔

    image

  11. merge

    • 序列容器:✔,O(n + m)

      • 仅限 list, forward_list

        • 两个链表已按 比较器规则 排序

        • 来自 *this 的元素始终先于来自 other 的元素
          且稳定
          即 *this 和 other 的等价元素的顺序不更改

      • vector和string:单一连续内存块
        deque:分段连续内存

        • 若合并结果存入新容器
          三者都需要开辟新内存空间

        • 若合并结果存入现有容器

          • vector 和 string
            可能需要扩容(重新分配内存)

          • deque扩容时无需移动旧元素
            只需新建一个或多个缓冲区(内存块)

        • O(n + m),与std::merge的效率完全一致

        • 需要元素复制 / 移动
          而且需要分配内存

        • 链表可以零复制合并
          而且没有内存分配 / 释放

    • 关联容器:×(c++11)

    • 哈希容器:×(c++11)

    返回值都是 void

    list<int> l1 = {1, 3, 5};
    list<int> l2 = {2, 4, 6};
    l1.merge(l2);
    //  l1={1,2,3,4,5,6}
    //  l2=∅
    
    // 迭代器和引用仍然有效
    
    struct Person {
        string name;
        int age;
        static bool byAge(const Person& a, const Person& b) {
            return a.age < b.age;
        }
    };
    
    
    list<Person> list1 = { {"Alice", 25}, {"Bob", 30} };
    list<Person> list2 = { {"Charlie", 20}, {"Diana", 35} };
    
    list1.merge(list2, Person::byAge);
    

列表操作

  1. sort

    • 序列容器:✔,O(nlogn),归并排序

      • 仅限 list, forward_list

      • 不采用快速排序
        索引 i 和 j 要求
        随机访问迭代器

      • 不采用希尔排序
        基于间隔序列的插入排序
        需跳跃式访问元素
        链表无法支持

      • 不采用堆排序
        父节点 i/2,子节点 2i+1
        随机访问迭代器

      • 采用归并排序
        顺序访问友好
        稳定排序
        原地合并
        (数组的合并需要临时空间)

      • 将链表元素复制到 vector
        排序后再复制回链表
        性能更高(空间换时间)

        • 适合元素复制成本低
          排序操作频繁
          或数据规模大时

        • 链表归并排序需要 O (n) 时间找中点

        • 频繁的指针跳转导致缓存命中率
          vector 内存连续
          CPU 缓存命中率高
          减少内存访问延迟

        • 复制:高效的内存块传输(如 memcpy)

    • 关联容器:×

    • 哈希容器:×

    返回类型都是 void

    list<int> lst = {3, 1, 4, 1, 5};
    lst.sort();  
    //默认升序:1, 1, 3, 4, 5
    
    lst.sort([](int a, int b) { return a > b; });  
    // 降序排序
    
  2. reverse

    • 序列容器:✔,O(n)

      • 仅限 list, forward_list

      • list:遍历链表
        交换每个节点的 prev 和 next 指针
        交换 头节点 和 尾节点

      • forward_list:n次头插法
        一次头插法 O(1)

    • 关联容器:×

      • 键比较函数不变,排序不变
    • 哈希容器:×

      • 本身无序,顺序无意义

    返回类型都是 void

    list<int> lst = {1, 2, 3};
    auto it = lst.begin();  // 指向1
    lst.reverse();
    // it 现在指向3
    // 反转后,原迭代器和引用仍有效
    
  3. unique

    • 序列容器:✔,O(n)

      • 仅限 list, forward_list

      • 移除连续重复的元素
        只保留第一个出现的元素

      • 移除所有重复元素
        先sort,再unique

    • 关联容器:×

      • 要么自动去重
        要么允许重复
    • 哈希容器:×

    返回类型都是 void(c++11)

    list<int> lst = {1, 1, 2, 2, 2, 3, 3, 1};
    lst.unique();
    // 结果:1, 2, 3, 1
    
    list<int> lst = {1, -1, 2, -2, 2, 3};
    lst.unique([](int a, int b) {
        return abs(a) == abs(b);
    });  // 结果:1, 2, 3
    // 支持传入二元谓词,用于定义 “重复”
    
  4. remove, remove_if

    • 序列容器:✔, O(n)

      • 仅限 list, forward_list

      • 移除链表中所有等于给定值的元素

    • 关联容器:×

    • 哈希容器:×

    返回类型都是 void(c++11)

    list<int> lst = {1, 2, 3, 2, 4};
    lst.remove(2);
    // lst = {1, 3, 4}
    

    remove_if 的函数参数是 一元谓词

    forward_list<int> flist = {1, 2, 3, 4, 5};
    flist.remove_if([](int n) {
     return n % 2 == 0; 
    }); // flist = {1, 3, 5}
    
  5. splice

    • 序列容器:✔

      • 仅限 list

      • forward_list: 没有 splice, 但有 splice_after

      对比

      • insert 值拷贝
        源容器不变
        可以接受 其他容器的迭代器

      • splice 移动节点,调整指针
        源链表的对应节点消失
        list 和 forward_list 不能相互拼接
        (list 不接受 forward_list 的迭代器
        反过来也是一样)

      image

      通用解释

      • list:元素将被插入到 pos 之前
        forward_list:元素将被插入到 pos 之后

        • 单向链表无法回溯
      • src:元素将从该链表移除

      重载函数

      1. 转移整个链表(均 包含begin 指向的元素)

      2. list:i 指向被转移的元素 本身
        forward_list:i 指向被转移元素的 前驱节点

        • 单向链表删除节点
          prev->next = node->next;
      3. 转移的区间
        list:包含 first,不包含 last
        forward_list:不包含 first,不包含 last

      void splice(iterator pos, list& src);  
      
      void splice(iterator pos, list& src, iterator i);  
      
      void splice(iterator pos, list& src, iterator first, iterator last);  
      
      • forward_list 的 splice_after
        形式跟以上相同

      • 被转移元素的迭代器仍然有效
        指向新链表中的相同元素

    • 关联容器:×

    • 哈希容器:×

    // 将 list1 的第一个元素移到末尾
    list1.splice(list1.end(), list1, list1.begin());
    // 自引用安全
    lst.splice(next(it), lst, it);
    

    position 不能在 [first, last) 范围内

查找

  1. find

    • 序列容器:✔,仅限 string

      • 函数参数为键
    size_t pos1 = str.find("world");   
    // 从位置5开始查找字符'o'
    size_t pos2 = str.find('o', 5);
    
    • 关联容器:✔,O(logn)

    • 哈希容器:✔,O(1)

    找到时:返回的迭代器指向
    第一个与目标键等价的元素

    • 是否等价由 比较器(关联容器)/ 等价性比较器(哈希容器)决定

    未找到时:返回 end

    auto it = container.find(key);
    
  2. count

    • 序列容器:×

      • 函数参数为键
    • 关联容器:✔,O(k + logn)

      • map, set
        键必须唯一
        返回值只能是 0 或 1
      • multimap, multiset
        允许键重复
        返回与目标 等价 的键的个数
        是否等价由比较器决定
    • 哈希容器:✔,O(1 + k)

      • 返回值同上
    size_t cnt = container.count(key);
    
  3. equal_range

    • 序列容器:×

      • 函数参数为键
    • 关联容器:✔,O(logn)

      • 第一个迭代器:lower_bound

      • 第二个迭代器:upper_bound

      • equal_range(key) 等价于

        make_pair(lower_bound(key), upper_bound(key));
        
      • 函数参数中的 key

        • 在容器中 找不到
          则两个迭代器 相同

        • 在容器中 能找到
          则两个迭代器 不同
          且第一个迭代器 指向key

      • 【pair.first, pair.second)
        包含所有与目标键 等价 的元素

        • 是否等价 由比较器决定
      • 稳定
        对于相同键的元素
        先插入的在前

    • 哈希容器:✔,O(1 + k)

      • 返回值同上
        但不是 lower_bound 和 upper_bound
    //返回值:pair<iterator, iterator>
    auto range = container.equal_range(key);
    
  4. lower_bound, upper_bound

    • 序列容器:×

      • 函数参数为键
    • 关联容器:✔,O(logn)

      • std::lower_bound 对非随机访问迭代器为 O(n)

      • 同样是在容器中找不到函数参数中的 key
        find 一定返回 end
        lower_bound
        只在 key 大于容器中的所有的键时
        返回 end

    • 哈希容器:×

      • 元素无序,无法定义不小于或大于的顺序
    //返回指向首个键 ≥ key 的元素的迭代器
    auto it = container.lower_bound(key);
    auto it = container.upper_bound(key);
    //返回指向首个键 > key 的元素的迭代器
    
    // 是否 ≥ 或 > 由比较器决定
    

观察器

  1. key_comp

    • 序列容器:×

    • 关联容器:✔

      • 默认比较器:less<Key>
        默认排序:升序(从小到大)

      • 返回 键比较器
        返回比较器的实例

    • 哈希容器:×

    map<int, string>m = {
          {3, "apple"},
          {5, "banana"}
      };
    less<int> k_comp = m.key_comp();
    cout << boolalpha;
    cout << k_comp(3, 5);
    // true
    
  2. value_comp

    • 序列容器:×

    • 关联容器:✔

      • 在 set 中与 key_comp 相同

      • 在 map 中比较键值对
        实际只比较键,忽略值

      • 返回 值比较器

    • 哈希容器:×

    map<int, string>m = {
          {3, "apple"},
          {5, "banana"}
      };
    
    auto it1 = m.find(3);
    auto it2 = m.find(5);
    
    map<int, string>::value_compare v_comp = m.value_comp();
    cout << boolalpha;
    cout << v_comp(*it1, *it2) << endl;
    // true
    
  3. hash_function

    • 序列容器:×

    • 关联容器:×

    • 哈希容器:✔

      • 相同元素的哈希值一定相同
        桶索引可能不同
        (哈希表的动态扩容)

      • 哈希冲突
        不同的键可以生成相同的哈希值

      • 返回哈希函数实例
        该函数用于计算键的哈希值

      • 返回类型
        默认是 hash<Key>
        容器模板参数中指定的哈希函数类型

    unordered_map<int, string> myMap;
    auto hasher = myMap.hash_function();
    int key1 = 100;
    cout << hasher(key1) << endl;
    // 使用哈希函数计算键的哈希值
    
  4. key_eq

    • 序列容器:×

    • 关联容器:×

    • 哈希容器:✔

      • 获取 相等性比较器
        获取 键等价性比较的 谓词
        判断两个键是否被视为相等

      • 默认比较器:equal_to<Key>

      • 哈希函数,相等性比较器,需要同时指定

    struct CaseInsensitiveHash {
        size_t operator()(const string& s) const {
            size_t h = 0;
            for (char c : s) {
                h = h * 31 + tolower(c);
            }
            return h;
        }
    };
    
    struct CaseInsensitiveEqual {
        bool operator()(const string& a, const string& b) const {
            if (a.size() != b.size()) return false;
            for (size_t i = 0; i < a.size(); ++i) {
                if (tolower(a[i]) != tolower(b[i])) return false;
            }
            return true;
        }
    };
    
    unordered_map<string, int, CaseInsensitiveHash, CaseInsensitiveEqual> myMap;
    CaseInsensitiveEqual eq = myMap.key_eq();
    cout << boolalpha;
    cout << eq("test", "Test") << endl;    // true
    cout << eq("test", "TEST!") << endl;   // false
    

桶和哈希

  1. bucket_count, max_bucket_count, bucket_size, bucket, load_factor, max_load_factor, rehash
    • 序列容器:×
    • 关联容器:×
    • 哈希容器:✔
posted on 2025-06-28 11:19  2024211826  阅读(7)  评论(0)    收藏  举报