C++STL的使用
C++ STL的使用手册
@version 1.2
@updated 20221108

共有函数
=:有赋值运算符以及复制构造函数。
begin():返回指向开头元素的迭代器。
end():返回指向末尾的下一个元素的迭代器。end() 不指向某个元素,它是末尾元素的后继。
size():返回容器内的元素个数。
max_size():返回容器 理论上 能存储的最大元素个数。依容器类型和所存储变量的类型而变。
empty():返回容器是否为空的一个 bool 值,即 begin() == end(),true 为空,false 为非空。
swap():交换两个容器。
clear():清空容器。
==/!=/</>/<=/>=:按 字典序 比较两个容器的大小。(比较元素大小时 map 的每个元素相当于 set<pair<key, value> >,pair 按 first 到 second 的顺序比较。无序容器不支持 </>/<=/>=)
迭代器
迭代器(Iterator)可以看作一个数据指针,用来访问和检查 STL 容器中元素的对象。主要支持两个运算符:

注意返回的是引用,是值,不是下标
vectordeque:随机访问迭代器,支持++--+n>[]listsetmap:双向迭代器,支持++--
序列式容器
vector
创建容器:如vector<int> dp(4, 1)可初始化dp为[1, 1, 1, 1].
元素访问
at()v.at(pos)返回容器中下标为pos的引用。如果数组越界抛出std::out_of_range类型的异常。operator[]v[pos]返回容器中下标为pos的引用。不执行越界检查。front()v.front()返回首元素的引用。back()v.back()返回末尾元素的引用。
可以认为,v[i]与*(v.begin()+i)等价。但,除vector string外,其他STL容器不支持后者的形式。
size()返回容器长度(元素数量),即std::distance(v.begin(), v.end())。insert()支持在某个迭代器位置插入元素、可以插入多个。复杂度与pos距离末尾长度成线性而非常数erase()删除某个迭代器或者区间的元素,返回最后被删除的迭代器。复杂度与insert一致。push_back(x)在末尾插入一个元素x,均摊复杂度:常数,最坏为线性复杂度。push_back会先创建元素x,再将这个元素拷贝或者移动到容器尾部(拷贝后会自行析构先前创建的这个元素)emplace_back()(C++11) 功能与上一相同。实现时,直接在容器尾部创建元素x,省去了拷贝或移动元素的过程。pop_back()删除末尾元素,常数复杂度。
deque
一个非常强大的数据结构,既支持 O(1) 随机读取,又支持 O(1) 的头部增删和尾部增删,不过有一定的额外开销。操作大同vector。(可认为底层是连续的)

push_front()在头部插入一个元素。pop_front()删除头部元素。push_back()在末尾插入一个元素。pop_back()删除末尾元素。front()返回首元素的引用。back()返回末尾元素的引用。任意位置插入一个元素:
deq.insert(iterator it, const T& x);任意位置删除一个元素:
deq.erase(iterator it);
list
双向链表,与deque大致相同,但是由于 list 的实现是链表,因此不提供随机访问的接口。若需要访问中间元素,则需要使用迭代器。相较于 deque ,如果需要大量的插入和删除,而不关心随机存取,则应使用list。
array(C++11)
operator=
array2 的每个元素重写 array1 对应元素
max_size
返回可容纳的最大元素数
fill
以指定值填充容器
arr.fill(1);
swap
交换,交换array的复杂度为:O(size)
operator==
按照字典序比较 array 中的值
std::get
访问 array 的一个元素
关联式容器
统一共有函数
find(x): 若容器内存在键为 x 的元素,会返回该元素的迭代器;否则返回end()。
如何获取值呢?使用访问方法。
erase(pos)删除迭代器为 pos 的元素,可结合find函数使用。erase(first,last)删除迭代器在 [first,last)范围内的所有元素。count(x): 返回容器内键为 x 的元素数量。lower_bound(x): 返回指向首个不小于 给定键的元素的迭代器。upper_bound(x): 返回指向首个**大于 **给定键的元素的迭代器。若容器内所有元素均小于或等于给定键,返回end()。size(): 返回容器内元素个数。
set
set 内部采用红黑树实现。平衡二叉树的特性使得 set 非常适合处理需要同时兼顾查找、插入与删除的情况。
insert(x)将元素 x 插入到set中。自动排序和去重。erase(x)删除值为 x 的 所有 元素,返回删除元素的个数。erase(first,last)删除迭代器在[first,last)范围内的所有元素。
set 在默认情况下的比较函数为 <(如果是非内置类型需要 重载 < 运算符)。然而在某些特殊情况下,我们希望能自定义 set 内部的比较方式。这时候可以通过传入自定义比较器来解决问题。
具体来说,我们需要定义一个类,并在这个类中重写仿函数 重载 () 运算符。(如,可以将重载了 () 运算符的结构体变量作为自定义比较函数传入优先队列等 STL 容器中。)
map
map 重载了 operator[],可以用任意定义了 operator < 的类型作为下标(在 map 中叫做 key,也就是索引)。
通过向
map中插入一个类型为pair<Key, T>的值可以达到插入元素的目的,例如mp.insert(pair<string,int>("Alan",100));可以直接通过下标访问来进行查询或插入操作。例:
mp["Alan"]=100。利用下标访问 时,如果map中不存在相应键的元素,会自动在map中插入一个新元素,并将其值设置为默认值(对于整数,值为零;对于有默认构造函数的类型,会调用默认构造函数进行初始化)erase(key)函数会删除键为key的 所有 元素。返回值为删除元素的数量。对于每个
map里的元素,可以使用.first获取key,使用second获取value。
无序关联式/哈希适配容器
四种基于哈希实现的无序关联式容器:unordered_set,unordered_multiset,unordered_map,unordered_multimap。
其操作与关联式容器类似。而平均时间复杂度是O(1),优势在我。而如果需要进行key的二分查找(lower_bound),则建议使用有序关联式容器。
unordered_map
常用于作为哈希表的模板,其对[]的重载赋予了它数组般的特性存在。
unordered_set
基于哈希表实现的【桶】。
set底层是红黑树,count时间复杂度就是O(logN)。
容器适配器
为什么称为容器适配器呢,是因为其内部的实现是基于vector deque 等等,其原理可以参考《STL源码剖析》。
后进先出的stack
仅支持查询或删除最后一个加入的元素(栈顶元素),不支持随机访问。
top()访问栈顶元素(如果栈为空,此处会出错)push(x)向栈中插入元素 xpop()删除栈顶元素
先进先出的queue
front()访问队首元素(如果队列为空,此处会出错)push(x)向队列中插入元素 xpop()删除队首元素
优先队列
top()访问堆顶元素(此时优先队列不能为空)push(x)插入元素,并对底层容器排序pop()删除堆顶元素(此时优先队列不能为空)
以上pop方法返回void,不返回已删除元素的值。
优先级的定义:
对于数字,一般是值大者优先。即默认为(大 根堆):
priority_queue<int, vector<int>, less<int> > pq;第二个参数是内部实现方式;第三个参数 less表示数字大的优先级越大。如果是
greater<int>,则为数字小者优先级大。 优先级大者,位于top。可以通过类似于关联式容器的方式定义cmp。如最大堆。参见
set章节。
此容器对于重复元素入堆的情况,为比较随意的,所以,如果有重复元素,最好经过处理再采取对应的算法,或者调整入堆策略。
在这里给一个模板:
pair的常见用法
头文件:<utility>
可当作(first,second…)两个元素的结构体,按照正常的结构体访问。
pair的默认比较方式是:先比较first,再比较second。
string的常见用法
string的实现形式类似于字符型vector,支持push_back、直接赋值(注意使用双引号)和下标访问。只支持cin cout,不支持printf等。
可以通过加减运算符实现字符串拼接和删减、比较运算符进行字典序比较。
substr(pos,len)方法截取子串。时间复杂度是O(len)。注意第二个参数是长度!find(x,pos)指定了开始寻找的位置为下标pos上面的共有函数(
erasefind等)也是支持的。复杂度都是O(n)
STL算法
在《特性》篇也介绍有一些用法。
find_end:逆序查找。find_end(v.begin(), v.end(), value)。nth_element:按指定范围进行分类,即找出序列中第 n 大的元素,使其左边均为小于它的数,右边均为大于它的数。nth_element(v.begin(), v.begin() + mid, v.end(), cmp)或nth_element(a + begin, a + begin + mid, a + end, cmp)next_permutation:将当前排列更改为 全排列中的下一个排列。如果当前排列已经是 全排列中的最后一个排列(元素完全从大到小排列),函数返回false并将排列更改为 全排列中的第一个排列(元素完全从小到大排列);否则,函数返回true。next_permutation(v.begin(), v.end())或next_permutation(v + begin, v + end)。算法实现:Leetcode-offer2reverse(vec.begin(), vec.end())可以获得序列式容器的反转。
bitset
通过固定的优化,使得一个字节的八个比特能分别储存 8 位的 0/1。
bitset(): 初始化每一位都是false。bitset(int val): 设为val的二进制形式。bitset(const string& str): 设为 01 串str。
operator []: 访问其特定的一位。operator ==/!=: 比较两个bitset内容是否完全一样。operator &/&=/|/| =/^/^=/~: 进行按位与/或/异或/取反操作。bitset只能与bitset进行位运算,若要和整型进行位运算,要先将整型转换为bitset。operator <>/<<=/>>=: 进行二进制左移/右移。operator <>: 流运算符,这意味着你可以通过cin/cout进行输入输出。count(): 返回true的数量。size(): 返回bitset的大小。_Find_first(): 返回bitset第一个true的下标,若没有true则返回bitset的大小。_Find_next(pos): 返回pos后面(下标严格大于pos的位置)第一个true的下标,若pos后面没有true则返回bitset的大小。any(): 若存在某一位是true则返回true,否则返回false。none(): 若所有位都是false则返回true,否则返回false。all():C++11,若所有位都是true则返回true,否则返回false。
以下三个函数,若不传入参,对所有bit都执行对应的操作。
set(pos, val = true): 将某一位设置成true/false。reset(pos): 将某一位设置成false。相当于set(pos, false)。flip(pos): 翻转某一位。
参考资料:
OI-wiki
《算法笔记》
最后更新于
这有帮助吗?