文章目录
前言
C++ 标准模板库 (STL, Standard Template Library):包含一些常用数据结构与算法的模板的 C++ 软件库,其包含六个组件——算法 (Algorithms)、容器 (Containers)、仿函数 (Functors)、迭代器 (Iterators),适配器以及空间适配器。
- 1、容器:存放数据
- 2、算法:操作数据
- 3、迭代器:
算法
通过迭代器
操作容器数据
- 4、仿函数:为算法提供更多的
策略
- 5、适配器:为算法提供更多参数的接口
- 6、空间配置器:为算法和容器动态分配、管理空间
示例:
- 算法:
sort(a.begin(), a.end())
- 容器:
priority_queue<int> pq
- 仿函数:
greater<int>()
- 迭代器:
vector<int>::iterator it = a.begin()
一、容器
容器库是一些通用的类模板与算法的汇集,允许程序员简单地实现如队列、链表和栈这样的常见数据结构。
主要常用的容器如下所示:
- 顺序容器: array、 vector、 deque、list
- 关联容器: set、 map、multiset、 multimap
- 无序关联容器、unordered_set、 unordered_map、unordered_multiset、unordered_multimap
- 容器适配器:stack、 queue、priority_queue
- 字符串:string (basic_string<char>)
- 对与元组: pair、tuple
1. 向量 vector
std::vector
是 C++ 标准库中的一个模板类,用于表示动态数组。与普通数组不同,vector 能够自动调整大小,并提供了一些方便的成员函数来进行元素的管理。std::vector 位于头文件#include <vector>
中。
1.1常用成员函数
1.1.1构造函数
vector<类型> arr(长度, [初值])
时间复杂度: O ( n ) O(n) O(n)
常用的一维和二维数组构造示例,高维也是一样的(就是会有点长).
vector<int> arr; // 构造int数组
vector<int> arr(100); // 构造初始长100的int数组
vector<int> arr(100, 1); // 构造初始长100的int数组,初值为1
vector<vector<int>> mat(100, vector<int> ()); // 构造初始100行,不指定列数的二维数组
vector<vector<int>> mat(100, vector<int> (666, -1)) // 构造初始100行,初始666列的二维数组,初值为-1
构造二维数组的奇葩写法,千万别用:
vector<int> arr[100]; // 正确,构造初始100行,不指定列数的二维数组,可用于链式前向星存图
vector<int> arr[100](100, 1); // 语法错误!
vector<int> arr(100, 1)[100]; // 语法错误!
vector<int> arr[100] {
{
100, 1}, 这里省略98个 ,{
100, 1}}; // 正确但奇葩,使用列表初始化
1.1.2 访问元素
- 中括号运算符
operator[]
:使用索引访问元素,和一般数组一样的作用。时间复杂度: O ( 1 ) O(1) O(1) at
(size_type n):安全的访问
指定位置的元素front()
:返回第一个元素的引用back()
:返回最后一个元素的引用
1.1.3 大小和容量
size()
:获取当前 vector 的长度,时间复杂度: O ( 1 ) O(1) O(1)
for (int i = 0; i < arr.size(); i++)
cout << a[i] << endl;
- capacity():返回在重新分配内存之前 vector 可以容纳的元素数量。
resize(新长度, [默认值])
:调整 vector 的大小,时间复杂度: O ( n ) O(n) O(n)。- 如果是缩短,则删除多余的值
- 如果是扩大,且指定了默认值,则新元素均为默认值**(旧元素不变)**
- reserve(size_type n):调整 vector 的容量。
empty()
:判断 vector 是否为空。如果是空返回true
反之返回false
.时间复杂度: O ( 1 ) O(1) O(1)
1.1.4 修改元素
.push_back(元素)
:在 vector 尾接一个元素,数组长度 + 1 +1 +1..pop_back()
:删除 vector 尾部的一个元素,数组长度 − 1 -1 −1
时间复杂度:均摊 O ( 1 ) O(1) O(1)
// init: arr = []
arr.push_back(1);
// after: arr = [1]
arr.push_back(2);
// after: arr = [1, 2]
arr.pop_back();
// after: arr = [1]
arr.pop_back();
// after: arr = []
- insert(
iterator pos
, const T& value):在指定位置插入元素。这里的位置类型是iterator 。 - erase(iterator pos):删除指定位置的元素。
- clear():清空 vector 中的所有元素。时间复杂度: O ( n ) O(n) O(n)
// 使用 insert 和 erase 修改元素
arr.insert(arr.begin() + 2, 10); // 在索引 2 位置插入 10
arr.erase(arr.begin() + 4); // 删除索引 4 位置的元素
1.1.5 迭代器
- begin():返回指向第一个元素的
迭代器
。 - end():返回指向最后一个元素之后的
迭代器
。 - rbegin():返回指向最后一个元素的反向迭代器。
- rend():返回指向第一个元素之前的反向迭代器。
// 使用迭代器遍历 vector
for (auto it = arr.begin(); arr!= v3.end(); ++it)
{
std::cout << *it << " ";
}
1.2 适用情形
一般情况 vector
可以替换掉普通数组,除非该题卡常。
有些情况普通数组没法解决: n × m n\times m n×m 的矩阵, 1 ≤ n , m ≤ 1 0 6 1\leq n,m\leq 10^6 1≤n,m≤106 且 n × m ≤ 1 0 6 n\times m \leq 10^6 n×m≤106
- 如果用普通数组
int mat[1000010][1000010]
,浪费内存,会导致 MLE。 - 如果使用
vector<vector<int>> mat(n + 10, vector<int> (m + 10))
,完美解决该问题。
另外,vector
的数据储存在堆空间中,不会爆栈。
2.双端队列deque
std::deque 是 C++ 标准库中的一种双端队列容器
,它允许在序列的两端
进行高效的插入和删除操作。deque 的全称是 "double-ended queue"(双端队列)
。它可以看作是一个动态数组的扩展,可以在头部和尾部进行操作
。
2.1 常用成员方法
作用 | 用法 | 示例 |
---|---|---|
构造 | deque<类型> d |
deque<int> d; |
在前端插入元素 | .push_front(元素) |
d.push_front(1); |
在后端插入元素 | .push_back(元素) |
d.push_back(1); |
移除前端元素 | .pop_front() |
d.pop_front(); |
移除后端元素 | .pop_back() |
d.pop_back(); |
访问前/后端元素 | .front()/.back() |
int a = d.front()/back(); |
访问元素 | .at()/.operator[] |
int a = d.at(1);/d[1] |
查看大小 / 清空 / 判空 | .size()/.clear()/.empty() | 略 |
2.2 适用情形
std::deque 的内存布局可能会比 std::vector 更复杂,因为它通常使用多个内存块
来实现双端操作。这使得在两端操作时比 std::vector 更高效,但在内部存储和访问方面可能不如 std::vector 连续。
std::deque 在前端和后端的插入和删除操作是高效的(常数时间复杂度),而在中间进行插入或删除操作的性能类似于 std::vector,其需要在容器的两端频繁
进行插入和删除操作的场景中使用。
3.栈 stack
在C++中,栈(stack)是一个后进先出(LIFO, Last In First Out)
数据结构。C++标准库提供了一个 stack 类模板,位于 #include <stack>
头文件中,用于实现栈操作。栈的主要特点是只能在栈顶进行插入和删除操作
,这保证了数据的顺序性。 通过二次封装双端队列 (deque) 容器,实现先进后出的栈数据结构。
3.1 常用成员方法
作用 | 用法 | 示例 |
---|---|---|
构造 | stack<类型> stk |
stack<int> stk; |
将元素压入栈顶 | .push(元素) |
stk.push(1); |
移除栈顶元素 | .pop() |
stk.pop(); |
访问栈顶元素,但不移除它 | .top() |
int a = stk.top(); |
查看大小 / 清空 / 判空 | .size()/.pop()/.empty() | 略 |
3.2 适用情形
vector 也可以当栈用,vector 的 .back()
取尾部元素,就相当于取栈顶,.push_back()
相当于进栈,.pop_back()
相当于出栈。
注意事项: 不可访问内部元素
! 下面都是错误用法
for (int i = 0; i < stk.size(); i++)
cout << stk[i] << endl;
for (auto ele : stk)
cout << stk << endl;
4 队列queue
队列(queue)是一种先进先出(FIFO, First In First Out)
数据结构。它的基本操作包括入队(enqueue)和出队(dequeue),其中元素的入队发生在队列的尾部,出队发生在队列的头部
。C++标准库提供了一个 queue 类模板,位于 #include <queue>
头文件中,用于实现队列操作。通过二次封装双端队列 (deque) 容器,实现先进先出的队列数据结构。
4.1常用方法
作用 | 用法 | 示例 |
---|---|---|
构造 | queue<类型> que |
queue<int> que; |
进队,加入队尾 | .push(元素) |
que.push(1); |
出队,移除队首元素 | .pop() |
que.pop(); |
取队首 | .front() |
int a = que.front(); |
取队尾 | .back() |
int a = que.back(); |
查看大小 / 清空 / 判空 | .size()/.pop()/.empty() | 略 |
4.2适用情形
在图的广度优先搜索(BFS)算法中,队列用于记录待访问的节点,确保按照层次顺序访问图中的节点。在多线程或进程间通信中,队列用于实现消息的传递和处理
注意事项: 不可访问内部元素!下面都是错误用法
for (int i = 0; i < que.size(); i++)
cout << que[i] << endl;
for (auto ele : que)
cout << ele << endl;
5.优先队列 priority_queue
std::priority_queue
是 C++ 标准库中提供的一个容器适配器,头文件 #include <queue>
,它基于堆实现,主要用于高效地管理具有优先级的元素。它通常用于优先级队列
,能够保证每次访问或删除操作都是对当前最大或最小元素的操作(取决于堆的类型)。提供常数时间的最大元素查找,对数时间的插入与提取,底层原理是 二叉堆
。
主要特点
- 优先级:std::priority_queue 确保每次从队列中取出的元素都是当前队列中
优先级最高的元素
。 - 底层实现:std::priority_queue 通常使用最大堆(最大二叉堆)实现,底层是一个二叉堆,确保每个父节点的值都大于或等于其子节点的值。
- 操作:支持常见的优先队列操作,包括插入元素、访问和删除优先级最高的元素。
5.1 常用方法
5.1.1构造函数
template <class T, class Container = std::vector<T>, class Compare = std::less<typename Container::value_type>>
class priority_queue;
- T: 队列中
元素的类型
。- Container: 用于存储元素的
底层容器类型
,默认为std::vector<T>
。- Compare: 元素的比较函数对象,决定优先级的排序,默认为
std::less<T>
,即最大堆。
简化后:
priority_queue<类型, 容器, 比较器> pque
- 类型:要储存的数据类型
- 容器:储存数据的底层容器,默认为
vector<类型>
,竞赛中保持默认即可 - 比较器:比较大小使用的比较器,默认为
less<类型>
,可自定义
// 储存int的大顶堆
priority_queue<int> pq1;
// 储存int的小顶堆
priority_queue<int, vector<int>, greater<int>> pq2;
// 使用自定义比较函数(最小堆)
auto compare = [](int a, int b) {
return a > b; };
priority_queue<int, vector<int>, decltype(compare)> minHeap(compare);
std::greater<int>
是 C++ 标准库中的一个比较函数对象,用于定义大于比较操作
。它是一个模板类的实例,用于将比较函数封装为函数对象。使用 std::greater<int> 可以轻松地实现优先队列的最小堆(即小顶堆)
等场景。
5.1.2其他
作用 | 用法 | 示例 |
---|---|---|
进堆 | .push(元素) |
que.push(1); |
出堆(优先级最高) | .pop() |
que.pop(); |
取堆顶(优先级最高) | .top() |
int a = que.top(); |
查看大小 / 判空 | .size()/ .empty() | 略 |
进出队复杂度 O ( log n ) O(\log n)