c: 容器first,last,it: 迭代器key: 关键字pred: 谓词函数
Chapter 9
顺序容器
(均定义在同名头文件中)
vector快速随机访问, 尾部增删元素快deque快速随机访问, 头尾增删元素快list双向顺序访问, 任意位置增删元素快forward_list单向顺序访问, 任意位置增删元素快array快速随机访问, 不能增删元素string与vector相似
初始化
c(c1)拷贝c1c(n, t)加入n个值为t的元素c(b, e)加入迭代器b到e的元素的拷贝c{a, b, c, ...}用初始化列表赋值c.assign()可按初始化方式为容器赋值. 以初始化列表赋值使用c.assign({1,2,...})
关系运算符
当且仅当容器类型相同时可比较
逐个对应位置元素比较, 相同时比较下一个, 直到不同时元素较小者容器较小
c1 == c2, 当且仅当c1.size() == c2.size()且所有对应位置元素相等
插入
c.insert(it, ...)接收迭代器, 插入到迭代器对应的位置之前, 返回第一个插入的元素位置的迭代器
可选c.insert(it, val), c.insert(it, n, val), c.insert(it, first, last), c.insert(it, {1, 2, ...})
末尾插入多个值时使用c.insert(c.end(), ...)
c.emplace(args)用参数构造并插入元素
c.push_back() c.push_front()部分容器支持
swap(a, b)交换容器内容
iter_swap(it1, it2)交换两个迭代器指向的元素
访问
访问元素前先检查c.empty()
任意访问得到元素的引用
c.at(index)在下标越界时抛出异常, 从而确保下标合法
c.front() c.back()部分容器支持
不改变元素时使用cbegin(),cend(), 为底层const
删除
c.erase()接收迭代器, 返回指向删除的最后一个元素的下一个位置的迭代器
c.clear()清空容器, 返回void
c.pop_back() c.pop_front()部分容器支持
增删vector,string,deque的元素会导致迭代器/引用/指针失效
string特殊操作
string s(s2, pos, len)用字符串的一部分构造另一个字符串,len可选s.substr(pos, len)得到子串,len可选- 字符串的
insert()erase()可接收下标作为pos,insert(pos, s2)可插入s2字符串 s.append(args)在末尾插入s.replace(pos, len, args)替换字符.pos为下标,len为删除的长度s.replace(first, last, args)迭代器版本s.find(s1, pos)查找子串或字符,pos可选. 查找不到返回string::nposs.rfind(s1, pos)从右侧查找,pos以左s.find_first_of(args)s.find_last_of(args)s.find_first_not_of(args)查找args中的 (或不在args中的) 任意字符第一次 (或最后一次) 出现的位置s.compare(s1)比较字符串, 等于时返回0, 大于时返回正数, 小于时返回负数to_string()stoi()等用于转换
vector.reserve(n)预先分配n大小的空间
容器适配器
接收一个已有的容器类型, 使其行为看起来像另一种类型
stack定义在<stack>中, queue, priority_queue定义在<queue>中
可以直接使用std::stack<int> s (此时使用默认的容器), 也可指定容器std::stack<int, std::vector<int>> s
stack和queue默认基于deque, 可使用list和vectorpriority_queue默认基于vector, 可使用deque
都支持empty(), size(), pop(), push(), emplace()
stack和priority_queue使用top(), queue使用front()和back()
priority_queue
优先队列, 即堆
内置类型默认为最大堆priority_queue<int> max_pq;
内置类型最小堆:
#include <vector>#include <functional>std::priority_queue<int, std::vector<int>, std::greater<int>> min_pq; // 必须指定实现容器自定义比较器:
struct Compare { bool operator()(type a, type b) const { return a < b; // 返回true表示交换a, b顺序(a在b后, 与comp恰好相反) }}priority_queue<int, vector<int>, Compare> pq;重载类<运算符:
struct Type { std::string name; int priority;
bool operator<(const Type& other) const { return priority < other.priority; // 写法与自定义比较器相同 }};Chapter 10
STL算法
未特别标注的函数均在<algorithm>中
只读
find(first, last, val)查找val对应元素, 返回指向元素位置的迭代器, 若不存在则返回last
find_if(first, last, pred) 查找第一个使pred为true的元素, 返回指向其迭代器, 若不存在则返回last
find_if_not(first, last, pred)
accumulate(first, last, init)在<numeric>中. 对序列元素求和, 累加到init值上. 使用init类型定义的+运算, 返回值为init类型. 序列元素的类型必须匹配或能转换为init类型
equal(first1, last1, first2)用==判断两个序列是否相等, 返回bool. 元素类型无需相同
更改
fill(first, last, val)将范围中的每个元素设置为val
fill_n(it, n, val)将从*it开始的n个元素设置为val, 不检查越界问题
copy(first1, last1, first2)将序列1复制到序列2 (清空原序列2), 返回序列2指向最后一个复制的元素的下一个位置的迭代器. 序列2必须至少已经有last1 - first1个元素
- 可使用
back_inserter
replace(first, last, old, new) 将序列中old元素替换为new
replace_copy(first, last, res_first, old, new) 替换后传入res (清空原res), res必须至少已经有last - first个元素
for_each(first, last, fn)对范围内的所有元素调用fn. 如需修改元素, 应传入引用值, 返回值无效
transform(first, last, first2, fn)对范围内的所有元素调用fn并将返回值放入另一个位置, 即通过return修改值. first == first2时, 相当于改变原容器
重排
sort(first, last, comp) 按comp函数排序, 默认升序
bool comp(type a, type b)返回true时不交换a, b顺序(a在b前), 否则交换comp需满足严格弱序, 即反自反性, 反对称性, 传递性comp默认使用<functional>中定义的less<T>- 可以传入
greater<T>表示降序 - 依赖于
T定义的<运算符
- 可以传入
stable_sort(first, last, comp)排序时保持相等元素的原有顺序
reverse(first, last)反转容器
remove(first, last, val)将所有值等于val的元素移动到末尾, 返回指向第一个val元素的迭代器
- 之后调用
c.erase(it, end)删除
(C++20)erase(c, val)直接删除容器中所有值等于val的元素
unique(first, last) 将连续的重复元素保留一个, 其余放到末尾冗余区域. 返回指向第一个冗余元素的迭代器
- 之后调用
c.erase(it, end)删除重复元素 - 如需全局去重, 需先排序
partition(first, last, pred) 将序列分组, 使pred为true的元素排在第一部分, 否则排在第二部分. 返回指向第二部分第一元素的迭代器
stable_partition(first, last, pred) 相同分组的元素保持原有顺序
链表算法
用于list和forward_list
l.merge(l2)对有序链表归并, 升序. 无返回值,l为归并后结果l.merge(l2, comp)自定义排序归并l.remove(val)l.remove_if(pred)直接移除, 不需要erase()l.reverse()翻转l.sort()l.sort(comp)l.unique()l.unique(pred)直接去重, 不需要erase()l.splice(it, l2)将l2中所有元素移动到it指向位置之前, 并从l2中删除l.splice(it, l2, it2)将it2指向的元素移动到it之前- 另有
fl.splice_after()用于forward_list
lambda表达式
形式: [capture_list](parameter_list) -> return_type {function_body}
参数列表和返回类型可忽略, 忽略返回类型时自动推断
当且仅当局部变量需要放入捕获列表
-
值捕获
[arg]: 捕获为局部变量的拷贝, 在lambda创建时拷贝, 储存在其中, 为const类型. 后续对外部变量的修改不影响lambda内部 -
引用捕获
[&arg]: 捕获为局部变量的引用. 使用lambda时需保证该变量存在 -
隐式捕获: 自动推断捕获的变量
[=]全部值捕获,[&]全部引用捕获[=, &args]默认值捕获,args给出的变量引用捕获,[&, =args]相反
在参数列表和返回类型中加入mutable可修改值捕获的变量const拷贝
绑定参数 (偏函数)
<functional>中的bind(), 用法为auto newCallable = bind(callable, arg_list)
arg_list与callable的参数一一对应, 传入需绑定的参数后, 无需绑定的对应参数使用占位符_1, _2, ...
- 占位符定义在
std::placeholders中 - 占位符顺序可调换, 此时
newCallable的对应参数传递也调换 - 绑定的参数以拷贝传递
示例: f(a, b, c) {}; auto f1 = bind(f, 5, _1, 6);
如需以引用绑定参数, 使用<functional>中的ref()或cref()包裹该参数
迭代器
定义在<inserter>中
插入迭代器: 在为迭代器赋值it = t时插入元素, *it, ==it仍返回it
种类
back_inserter: 使用push_back()front_inserter: 使用push_front(), 因此插入序列反转inserter: 使用insert(),inserter(c, it)第二个参数传入一个迭代器, 插入到该迭代器之前, 因此插入序列顺序不变
常用于存入新容器的操作 (copy(), transform())
使用方法: back_insertor(c)返回c的迭代器
-
iostream迭代器-
istream_iterator<T> in(is): 从is中读取类型为T的值. 不填(is)时返回EOF-
*in, ++in可以正常使用 -
输入时使用
while(is != eof) -
istream_iterator<int> in(cin), eof;vector<int> vec(in, eof);
直接从
cin输入构造vector, 或直接用于泛型算法
-
-
ostream_iterator<T> out(os, d): 将类型为T的值输出到os中,d为C风格字符串(字面常量或字符数组), 每次输出后打印dout = k时输出*out, ++out返回outfor (auto e : vec) out = e;输出容器copy(vec.begin(), vec.end(), out)也可打印
-
-
反向迭代器:
c.rbegin(), c.rend()- 依然用
++表示正向 (向前) it.base()返回正向迭代器, 指向it的右一个位置- 以保证
[rbegin(), it)与[it.base(), end())指向相同范围 (反向)
- 以保证
sort(c.rbegin(), c.rend())可以直接递减排列find()等查找类算法可以从右查找- 返回的迭代器依然是反向迭代器, 通过
base()转换
- 返回的迭代器依然是反向迭代器, 通过
- 拷贝类算法可以拟序输出
- 依然用
迭代器分类:
| 类型 | 支持操作 | 示例 |
|---|---|---|
| 输入迭代器 | 只读, 单次遍历, 递增 | istream_iterator |
| 输出迭代器 | 只写, 单次遍历, 递增 | ostream_iterator, back_inserter |
| 前向迭代器 | 读写, 多次遍历, 递增 | forward_list |
| 双向迭代器 | 读写, 多次遍历, 递增递减 | list, map, set |
| 随机访问迭代器 | 读写, 多次遍历, 和整数值加减, 和迭代器比较, 和迭代器相减, 下标访问 | vector,string, deque, array |
操作
std.move(it, n)定义在<iterator>中, 返回将迭代器递增指定步数的新迭代器, 不修改原迭代器std.prev(it, n)定义在<iterator>中, 递减指定步数, 用于双向迭代器
Chapter 11
关联容器
(均定义在同名头文件中)
-
map关键字-值对的集合, 自动按key升序排序 -
set关键字的集合, 自动升序排序 -
unordered_map使用hash存储值, 无序而更快 -
unordered_set -
均有
multi版本, 定义在对应原版头文件中
关键字
关键字不可更改
有序容器关键字的类型需可<比较, 比较函数满足严格弱序
- 定义
<方法 - 传入自定义方法, 初始化方式为:
map<type1, type2, decltype(func)*> myMap(func);其中func为自定义比较函数
无序容器关键字的类型需可哈希和可==比较
==重载方式相同- 传入哈希函数, 初始化方式为:
size_t hasher(const type2& elem) { return hash<int>()(elem.id()); // 内置的hash函数}unordered_map<type1, type2, decltype(hasher)*> myMap(hasher); // 假设在类中已重载==. 也可以同时传入自定义==函数<pair>
定义在<utility>中
初始化: pair<T1, T2> p{v1, v2}
访问: p.first, p.second
(C++17) 结构化绑定auto [fst, snd] = pair赋值fst, snd
当first和second分别相等时, p1 == p2
在函数中返回时, 可使用return {v1, v2}
关键字/值类型
key_type关键字类型mapped_typemap中值类型value_type- 对于
set, 与key_type相同 - 对于
map, 为pair<const key_type, mapped_type>
- 对于
初始化
set s{1, 2, 3}, map m{{1, 2}, {3, 4}, {5, 6}}
set(c.begin(), c.end())
非multi容器中重复关键字的元素会自动舍去
map不能自动推断泛型类型
插入
c.insert(value)添加单一元素- 为非
multi类型时, 只有关键字不存在时才会插入. 返回一个pair,first为指向插入元素或已存在元素的迭代器,second为指示插入是否成功的bool值. - 为
multi类型时总会插入成功, 返回指向新元素的迭代器
- 为非
c.emplace(args)c.insert(first, last)迭代器插入, 返回voidc.insert(init_list)返回voidc.insert(pos, value)pos指示从何处开始搜索新元素应该存储的位置, 返回一个迭代器c[k] = val在map中, 对k进行值初始化, 并将val赋值- 只写
c[k]时, 只进行值初始化
- 只写
有序容器按比较函数升序存储
multi类型中相同关键字元素连续存储
访问
c[key]
- 只有非
multi字典可用 - 若关键字为
key元素存在, 返回对应值; 若不存在, 添加该关键字元素, 进行值初始化, 返回值 - 返回为左值, 可以直接进行写入(如
++my_map[1]) const类型和const函数内map不能使用[], 需用at()
c.at(key)若不含key元素, 抛出异常
c.find(key)查找对应关键字的元素, 返回迭代器. 若不存在, 返回c.end()
c.count(key)返回对应关键字的元素数量
- 用于查询元素是否存在时,
if(c.count(key))比if(c.find(key) != c.end())更快
(C++20) set.contains(key)查找set中元素是否存在
迭代器指向value_type. set的迭代器始终只读, map的迭代器不可修改first值
(C++17) for (auto& [fst, snd] : map)结构化绑定遍历
c.equal_range(key)在multi容器中, 返回一个迭代器的pair, 指向关键字等于key的元素的范围. 若key不存在, 均指向c.end()
在multimap中查找同一关键字的所有元素:
for (auto [it, end] = m.equal_range(key); it != end; ++it) cout << it->second << endl;删除
c.erase(key)删除所有关键字为key的元素, 返回size_type大小为删除元素数量
c.erase(it)与c.erase(first, last)返回指向最后一个删除的元素的下一个位置的迭代器



