STL(标准模板库)中的各种容器和算法的使用方法。

推荐引入万能头文件:

  1. #include <bits/stdc++.h>
  2. using namespace std;//使用std命名空间

vector

创建vector

  1. vector<int> v; // 创建一个空的vector,元素类型为int
  2. vector<int> v1(10); // 创建一个含有10个元素的vector,所有元素默认初始化为0
  3. vector<int> v2(10, 42); // 创建一个含有10个元素的vector,所有元素初始化为42
  4. vector<int> v3 = {1, 2, 3, 4, 5}; // 使用列表初始化创建一个vector

访问元素

  1. int x = v[0]; // 访问第一个元素
  2. int y = v.at(1); // 使用at()函数访问第二个元素,at()会进行边界检查

修改元素

  1. v[0] = 10; // 修改第一个元素,O(1)
  2. v.push_back(20); // 在vector末尾添加一个元素,O(1)
  3. v.pop_back();//删除末尾元素,O(1),请注意保证vector非空

遍历vector

  1. for (int i = 0; i < v.size(); ++i) {
  2. cout << v[i] << ' ';
  3. }
  4. cout << endl;
  5. // 或者使用范围for循环
  6. for (int elem : v) {
  7. cout << elem << ' ';
  8. }
  9. cout << endl;
  10. // 如果vector存储的是pair类型或结构体,C++17以上版本可以使用结构化绑定来枚举
  11. vector<pair<int, int>> v_pair;
  12. // &表示引用枚举,不加&就是默认拷贝枚举
  13. for(const auto &[a, b] : v_pair){
  14. cout << x << ' ' << y << '\n';
  15. }

查询vector的大小

  1. int size = v.size(); // 返回vector中元素的数量
  2. //判断vector是否为空
  3. if(v.empty()) ...
  4. if(v.size()) ...

清空vector

  1. v.clear(); // 移除所有元素,size变为0,时间复杂度O(n)

stack

stack是栈,一种后进先出(Last In First Out)的容器,它仅维护栈顶,支持入栈(push)、查询栈顶(top)、出栈(pop)、查询大小(size)操作。

常用于“单调栈”、“括号匹配”、“dfs”、“Tarjan求强连通分量”、“波兰表达式(计算器)”等算法或数据结构中。

初始化

  1. stack<int> stk;//创建一个空栈,栈不允许列表初始化或填充相同元素
  2. //但是可以从已有的栈进行拷贝构造
  3. stack<int> stk2(stk);
  4. stack<int> stk3 = stk2;

入栈

  1. stk.push(10);//stk = [10(top)]
  2. stk.push(20);//stk = [10, 20(top)]
  3. stk.push(50);//stk = [10, 20, 50(top)]
  4. cout << stk.top() << '\n';//50, stk = [10, 20, 50(top)]

取出栈顶元素

在C++中,top()函数仅仅是取出栈顶元素,不会将栈顶元素pop()掉,请注意!

  1. cout << stk.top() << '\n';//50, stk = [10, 20, 50(top)]

出栈

讲个笑话:如果你问一个人push的反义词是什么,如果他说是pop,那么他肯定是一个程序员。

  1. //弹出栈顶元素,注意判断非空!
  2. if(stk.size())stk.pop();//stk = [10, 20(top)]
  3. cout << stk.top() << '\n';//20, stk = [10, 20(top)]

获取栈大小(元素个数),判空

  1. cout << stk.size() << '\n';
  2. if(stk.empty())...//栈为空

清空栈

  1. while(stk.size())stk.pop();//时间复杂度O(n)

在stack中不允许遍历,但是如果我们手写栈(或者干脆用vector好了),就可以实现这个功能。

手写栈

手写栈非常简单,用一个top变量表示栈顶下标即可,以下标1作为栈底。

  1. int stk[N], top = 0;
  2. //入栈
  3. stk[++ top] = x;
  4. //出栈
  5. top --;
  6. //取出栈顶元素
  7. cout << stk[top] << '\n';
  8. //获取大小
  9. cout << top << '\n';
  10. //判断是否为空
  11. if(top)...//栈非空
  12. //遍历栈
  13. for(int i = 1;i <= top; ++ i)...
  14. //甚至可以在单调栈上进行二分

queue

queue提供了先进先出(First In First Out)的数据结构。队列在尾部添加元素,在头部删除元素。

常见应用有:模拟、约瑟夫环、bfs、分支限界搜索、单调队列等算法。

创建队列

  1. queue<int> q; // 创建一个int类型的队列

添加元素(入队)

使用push()函数将元素添加到队列的尾部。

  1. q.push(10); // 将10添加到队列尾部
  2. q.push(20);
  3. q.push(30);

删除元素(出队)

使用pop()函数删除队列的头部元素。

  1. q.pop(); // 删除队列头部元素,即10

访问队列头部元素

使用front()函数获取队列头部元素的引用。

  1. int frontElement = q.front(); // frontElement 现在是20

访问队列尾部元素

使用back()函数获取队列尾部元素的引用。

  1. int backElement = q.back(); // backElement 现在是30

检查队列是否为空 / 获取队列大小

使用empty()函数检查队列是否为空。

  1. if (q.empty()) {
  2. cout << "队列是空的" << endl;
  3. } else {
  4. cout << "队列不是空的" << endl;
  5. }
  6. int size = q.size(); // size 现在是2

示例代码

以下是一个使用queue的完整示例:

  1. #include <iostream>
  2. #include <queue>
  3. using namespace std;
  4. int main() {
  5. queue<int> q;
  6. // 添加元素
  7. q.push(10);
  8. q.push(20);
  9. q.push(30);
  10. // 输出队列头部元素
  11. cout << "队列头部元素:" << q.front() << endl;
  12. // 删除队列头部元素
  13. q.pop();
  14. // 再次输出队列头部元素
  15. cout << "队列头部元素(删除后):" << q.front() << endl;
  16. // 输出队列大小
  17. cout << "队列大小:" << q.size() << endl;
  18. return 0;
  19. }

运行上述代码,输出结果如下:

  1. 队列头部元素:10
  2. 队列头部元素(删除后):20
  3. 队列大小:2

queue和stack一样,不允许遍历。

deque

deque是queue的升级版,全称为double-ended queue,队头和队尾都支持入队和出队,同时还支持遍历,所有操作时间复杂度均为 O(1)。

常见应用是单调队列。

声明

  1. deque<int> dq;

常用操作

  1. dq.push_front(x);//在队头推入x
  2. dq.push_back(x);//在队尾推入x
  3. dq.front();//获取队头元素
  4. dq.back();//获取队尾元素
  5. //获取队列大小
  6. dq.size();
  7. //获取队列是否为空
  8. dq.empty();
  9. //以下两个操作注意判断队列非空
  10. dq.pop_front();//弹出队头
  11. dq.pop_back();//弹出队尾

遍历deque

  1. //用迭代器遍历
  2. for(auto it = dq.begin(); it != dq.end(); it ++)
  3. {
  4. cout << *it << ' ';
  5. }
  6. //用基于范围的for循环
  7. for(const auto &val : dq)cout << val << ' ';

priority_queue

优先队列,也叫做“堆”,仅维护最大/最小的元素,可以在较小的时间复杂度内获取某个元素集合的最大或最小值。

优先队列常用于贪心、优化dp、构造、dijkstra、prim等问题或算法中,应用非常广泛。

声明

  1. //默认为大根堆
  2. priority_queue<int> pq;
  3. //改为小根堆
  4. priority_queue<int, vector<int>, greater<int> > pq;
  5. //自定义比较函数常用方法
  6. //方法一:全局函数,传入函数指针用decltype转换
  7. bool cmp(const int &u, const int &v){
  8. return u < v;//大根堆
  9. }
  10. priority_queue<int, vector<int>, decltype(&cmp) > pq(cmp);
  11. //方法二:匿名函数用cmp变量存储,传入变量
  12. auto cmp = [](const int &u, const int &v){
  13. return u < v;//大根堆
  14. };
  15. priority_queue<int, vector<int>, decltype(cmp)> pq(cmp);
  16. //方法三:struct重载()运算符
  17. struct cmp{
  18. bool operator () (const int &u, const int &v){
  19. return u < v;//大根堆
  20. }
  21. };
  22. priority_queue<int, vector<int>, cmp> pq;

常规操作

  1. //取出堆顶元素,时间复杂度O(1)
  2. cout << pq.top() << '\n';//注意保证pq非空
  3. //入堆,时间复杂度O(logn),n为堆内元素个数
  4. pq.push(x);
  5. //出堆,时间复杂度O(logn),n为堆内元素个数
  6. pq.pop();//注意保证pq非空
  7. //获取堆内元素个数,即堆的大小
  8. cout << pq.size() << '\n';
  9. 优先队列为树形结构,不支持遍历(除非逐个出堆)。