构造函数
-
默认构造
- 序列容器:✔
- 关联容器:✔
- 哈希容器:✔
- 容器适配器:✔
-
初始化列表
-
序列容器:✔
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"} });
-
哈希容器:✔
-
容器适配器:×
-
-
移动构造
-
序列容器:✔,除了 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));
-
-
范围构造,拷贝构造,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);
-
-
count 个 value
-
序列容器:✔,除了array
初始化 n 个值为 val 的元素
val 默认值为 T()vector<int> v2(5); // 5个int(默认0)
string s2(5, 'a');
-
关联容器:×
-
哈希容器:×
-
-
自定义比较器(函数对象)
-
序列容器:×
-
关联容器:✔
- multimap 的比较器
只比较键,不比较值
map<int, string, greater<int>> map6;
- multimap 的比较器
-
哈希容器:✔
- unordered_multimap 的相等性比较器
只比较键,不比较值
unordered_set<int> set4(50); // 初始桶数=50 unordered_set<int, MyHash> set5(10, MyHash{}); unordered_set<int, MyHash, MyEqual> set6(5, MyHash{}, MyEqual{}); // 函数参数列表 可写可不写
- unordered_multimap 的相等性比较器
-
容器适配器:✔,仅限 priority_queue
priority_queue<int, vector<int>, greater<int>> pq; // 最小堆
-
-
自定义比较器(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
-
-
自定义比较器(函数指针)
-
序列容器:×
-
关联容器:✔
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
-
-
指定底层容器
-
其他的构造函数
string s3("hello"); string s4(s3, 1, 3); // 从s3的索引1开始,取3个字符 → "ell"
迭代器
-
begin, end, std::next(it, n), n 为正数, ++it
- 序列容器:✔
- 关联容器:✔
- 哈希容器:✔
- 任意位置的迭代器
哈希表的桶遍历
- 任意位置的迭代器
next 通过 ++it 执行 n 次自增(默认 n=1 )
-
rbegin, rend, std::next(it, n), n 为负数, --it
-
序列容器:✔,forward_list 除外
-
rbegin 和 rend 是反向迭代器
容器必须提供双向迭代器
或随机访问迭代器 -
forward_list:单向链表
只支持前向迭代器
-
-
关联容器:✔,逆序遍历O(n)
-
哈希容器:×
- 前向迭代器
只能 ++ 不能 --
不支持反向遍历
- 前向迭代器
-
-
cbegin, cend
- 序列容器:✔
- 关联容器:✔
- 哈希容器:✔
-
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
-
-
operator+, operator-
-
序列容器:✔
-
list, forward_list 除外
-
要求 随机访问迭代器
-
-
关联容器:×
-
哈希容器:×
-
元素访问
-
范围 for 循环
-
序列容器:✔
-
关联容器:✔
-
红黑树的中序遍历(按键排序)
-
稳定
对于相同键的元素
先插入的元素在前
-
-
哈希容器:✔
时间复杂度都是 O(n)
但常数因子不同
迭代器模式的语法糖
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; } // 直接引用元素,可修改原始数据
-
-
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
-
-
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
-
-
front, back
-
序列容器:✔,O(1)
- forward_list 无 back
存储尾指针 或 O(n) 都不理想
- forward_list 无 back
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;
-
-
-
operator*(不是乘法,是迭代器解引用)
-
序列容器:✔
- 返回元素的 非 const 引用
auto it = vec.begin(); *it = 10;
-
关联容器:✔
- 返回 const 键引用 + 非 const 值引用
- 键是 const 保证有序性
auto it = map1.begin(); it->second = "A";
-
哈希容器:✔
-
返回 const 键引用 + 非 const 值引用
-
禁止修改键
否则会导致哈希值变化
破坏元素在表中的位置
-
-
容量
-
size
- 序列容器:✔,
- forward_list(c++11)无 size
- 关联容器:✔
- 哈希容器:✔
- 容器适配器:✔
都是 O(1)
- 序列容器:✔,
-
empty
- 序列容器:✔
- 关联容器:✔
- 哈希容器:✔
- 容器适配器:✔
都是 O(1)
-
max_size
- 序列容器:✔
- 关联容器:✔
- 哈希容器:✔
array的 max_size() 等同于 size()
其他容器的 max_size() 无意义 -
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() 不包含该字符
-
-
assign
-
序列容器:✔
-
O(n + m),由 clear 与 insert 的时间复杂度相加得到
-
array 除外
清空容器相当于 clear
array 不支持 clear -
先 清空 所有原有元素
-
相当于 clear,size 变为0
-
capacity 不变
-
assign 和 clear 在迭代器失效上完全一致
调用后所有迭代器、指针和引用立即失效
-
-
再 插入 新元素
-
-
关联容器:×
- 树的析构 O(n)
树的建立 O(nlogn)
- 树的析构 O(n)
-
哈希容器:×
- 为了查找、插入和删除
而非批量替换
- 为了查找、插入和删除
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);
-
-
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}
-
-
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
-
-
shrink_to_fit
-
序列容器:✔,O(n)
-
array, forward_list, list 除外
-
vector, string
请求容器将 capacity() 减少至 size()
释放多余内存 -
deque
请求释放未使用的内存块 -
迭代器、指针,引用 全部失效
内存重新分配
不同于 reserve
-
-
关联容器:×
-
哈希容器:×
container.shrink_to_fit(); // 返回类型 void
-
修改
-
clear
-
序列容器:✔,O(n)
-
array 除外,大小固定
-
vector, string
调用元素的析构函数
对于基本类型则直接清除值
但不释放内存
保留capacity -
deque
释放所有内存块 -
list, forward_list
释放所有节点内存
-
-
关联容器:✔,O(n)
- 释放所有节点内存
-
哈希容器:✔,O(n)
- 调用元素的析构函数
但保留 bucket 数组
不释放内存
- 调用元素的析构函数
-
容器适配器:×(c++11)
所有迭代器、引用和指针均失效
链表容器 + 关联容器 + 哈希容器的 end() 仍然有效//容器大小变为0 container.clear();
-
-
swap
-
序列容器:✔
- 交换内部指针或大小
不涉及元素的复制或移动
- 交换内部指针或大小
-
关联容器:✔
- 交换底层树结构的根指针
-
哈希容器:✔
- 交换 桶数组指针,哈希函数,比较器
bucket_count, size, load_factor
- 交换 桶数组指针,哈希函数,比较器
-
容器适配器:✔
- 交换底层容器
两容器适配器/两容器 的模板参数列表要完全相同
交换后,原容器的迭代器、引用和指针
指向新容器的元素
即交换前后, it 不变,ref 不变-
array 除外,迭代器仍指向原元素
即交换前后,it 改变,ref 改变 -
string 会失效
//array O(n), 其他 O(1) container1.swap(container2);
-
-
erase
-
序列容器:✔
-
forward_list 和 array 除外
-
forward_list 没有 erase,但有 erase_after
-
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);
-
-
哈希容器:✔
-
-
insert
-
序列容器:✔
-
forward_list 和 array 除外
-
forward_list 没有 insert,但有 insert_after
以下函数均适用
// 这个重载函数跟 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
-
-
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
-
-
-
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) 慢
- 提示插入位置不准确
-
哈希容器:✔
- 提示的作用有限
因元素位置由哈希值决定
- 提示的作用有限
-
-
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中构造,仅调用构造函数
-
-
关联容器:×
-
哈希容器:×
-
-
push_back, pop_back
-
序列容器:✔, O(1)
-
array, forward_list 除外
-
在 c++11, 返回类型都为 void
string str = "abc"; str.push_back('d'); // 尾部添加字符,变为"abcd" str.pop_back();
-
-
关联容器:×
- 元素按键排序
插入位置由键值决定
而非尾部
- 元素按键排序
-
哈希容器:×
- 元素根据哈希值自动分配位置
-
-
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}
-
-
关联容器:×
-
哈希容器:×
-
-
push, pop
- 序列容器:×
- 关联容器:×
- 哈希容器:×
- 容器适配器:✔
-
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);
-
列表操作
-
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; }); // 降序排序
-
-
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 // 反转后,原迭代器和引用仍有效
-
-
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 // 支持传入二元谓词,用于定义 “重复”
-
-
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}
-
-
splice
-
序列容器:✔
-
仅限 list
-
forward_list: 没有 splice, 但有 splice_after
对比
-
insert 值拷贝
源容器不变
可以接受 其他容器的迭代器 -
splice 移动节点,调整指针
源链表的对应节点消失
list 和 forward_list 不能相互拼接
(list 不接受 forward_list 的迭代器
反过来也是一样)
通用解释
-
list:元素将被插入到 pos 之前
forward_list:元素将被插入到 pos 之后- 单向链表无法回溯
-
src:元素将从该链表移除
重载函数
-
转移整个链表(均 包含begin 指向的元素)
-
list:i 指向被转移的元素 本身
forward_list:i 指向被转移元素的 前驱节点- 单向链表删除节点
prev->next = node->next;
- 单向链表删除节点
-
转移的区间
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) 范围内
-
查找
-
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);
-
-
count
-
序列容器:×
- 函数参数为键
-
关联容器:✔,O(k + logn)
- map, set
键必须唯一
返回值只能是 0 或 1 - multimap, multiset
允许键重复
返回与目标 等价 的键的个数
是否等价由比较器决定
- map, set
-
哈希容器:✔,O(1 + k)
- 返回值同上
size_t cnt = container.count(key);
-
-
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);
-
-
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 的元素的迭代器 // 是否 ≥ 或 > 由比较器决定
-
观察器
-
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
-
-
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
-
-
hash_function
-
序列容器:×
-
关联容器:×
-
哈希容器:✔
-
相同元素的哈希值一定相同
桶索引可能不同
(哈希表的动态扩容) -
哈希冲突
不同的键可以生成相同的哈希值 -
返回哈希函数实例
该函数用于计算键的哈希值 -
返回类型
默认是 hash<Key>
容器模板参数中指定的哈希函数类型
-
unordered_map<int, string> myMap; auto hasher = myMap.hash_function(); int key1 = 100; cout << hasher(key1) << endl; // 使用哈希函数计算键的哈希值
-
-
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
-
桶和哈希
bucket_count, max_bucket_count, bucket_size, bucket, load_factor, max_load_factor, rehash
- 序列容器:×
- 关联容器:×
- 哈希容器:✔