STL算法中常用知识点总结

C++ 标准模板库 (STL, Standard Template Library):包含一些常用数据结构与算法的模板的 C++ 软件库。其包含四个组件——算法 (Algorithms)、容器 (Containers)、仿函数 (Functors)、迭代器 (Iterators).

示例:

  • 算法:sort(a.begin(), a.end())
  • 容器:priority_queue pque
  • 仿函数:greater()
  • 迭代器:vector::iterator it = a.begin()

1 前言

STL 作为一个封装良好,性能合格的 C++ 标准库,在算法竞赛中运用极其常见。灵活且正确使用 STL 可以节省非常多解题时间,这一点不仅是由于可以直接调用,还是因为它封装良好,可以让代码的可读性变高,解题思路更清晰,调试过程 往往 更顺利。

不过 STL 毕竟使用了很多复杂的结构来实现丰富的功能,它的效率往往是比不上自己手搓针对特定题目的数据结构与算法的。因此,STL 的使用相当于使用更长的运行时间换取更高的编程效率。因此,在实际比赛中要权衡 STL 的利弊,不过这一点就得靠经验了。

接下来,我会分享在算法竞赛中常用的 STL 容器和算法,对于函数和迭代器,就不着重展开讲了。

2 常用容器

2.1 内容总览

打勾的是本次将会详细讲解的,加粗的是算法竞赛中有必要学习的。

  • 顺序容器

    • [ ] array
    • [√] vector
    • [ ] deque
    • [ ] forward_list
    • [ ] list
  • 关联容器

    • [√] set
    • [√] map
    • [ ] multiset
    • [ ] multimap
  • 无序关联容器

    • [ ] unordered_set
    • [ ] unordered_map
    • [ ] unordered_multiset
    • [ ] unordered_multimap
  • 容器适配器

    • [√]stack
    • [√] queue
    • [√]priority_queue
    • [ ] flat_set
    • [ ] flat_map
    • [ ] flat_multiset
    • [ ] flat_multimap
  • 字符串

    • [√] string (basic_string\)
  • 对与元组

    • [√] pair
    • [ ] tuple

2.2 向量 vector

#include

连续的顺序的储存结构(和数组一样的类别),但是有长度可变的特性。

2.2.1 常用方法

构造

vector<类型> arr(长度, [初值])

时间复杂度:O(n)

常用的一维和二维数组构造示例,高维也是一样的(就是会有点长).

vector arr;         // 构造int数组
vector arr(100);    // 构造初始长100的int数组
vector arr(100, 1); // 构造初始长100的int数组,初值为1

vector> mat(5,vector(6));//构造五行六列的二维数组
vector> mat(100, vector ());       // 构造初始100行,不指定列数的二维数组
vector> mat(100, vector (666, -1)) // 构造初始100行,初始666列的二维数组,初值为-1

构造二维数组的奇葩写法,千万别用:

vector arr[100];         // 正确,构造初始100行,不指定列数的二维数组,可用于链式前向星存图
vector arr[100](100, 1); // 语法错误!
vector arr(100, 1)[100]; // 语法错误!
vector arr[100] {
  {100, 1}, 这里省略98个 ,{100, 1}}; // 正确但奇葩,使用列表初始化
尾接 & 尾删
  • .push_back(元素):在 vector 尾接一个元素,数组长度 +1.
  • .pop_back():删除 vector 尾部的一个元素,数组长度 −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 = []
中括号运算符

和一般数组一样的作用

时间复杂度:O(1)

获取长度

.size()

获取当前 vector 的长度

时间复杂度:O(1)

for (int i = 0; i < arr.size(); i++)
    cout << a[i] << endl;
清空

.clear()

清空 vector

时间复杂度:O(n)

判空

.empty()

如果是空返回 true 反之返回 false.

时间复杂度:O(1)

改变长度

resize改长时默认多的位置补0,改短时多的尾部位置被删去

.resize(新长度, [默认值])

eg:arr.resize(5,3) //新长度为5,多的尾部位置初值为3

修改 vector 的长度

  • 如果是缩短,则删除多余的值
  • 如果是扩大,且指定了默认值,则新元素均为默认值(旧元素不变)

时间复杂度:O(n)

2.2.2 适用情形

一般情况 vector 可以替换掉普通数组,除非该题卡常。

有些情况普通数组没法解决:n×m 的矩阵,1≤n,m≤106 且 n×m≤106

  • 如果用普通数组 int mat[1000010][1000010],浪费内存,会导致 MLE。
  • 如果使用 vector> mat(n + 10, vector (m + 10)),完美解决该问题。

另外,vector 的数据储存在堆空间中,不会爆栈。

2.2.3 注意事项

提前指定长度

如果长度已经确定,那么应当直接在构造函数指定长度,而不是一个一个 .push_back(). 因为 vector 额外内存耗尽后的重分配是有时间开销的,直接指定长度就不会出现重分配了。

在构造时指定数组长度有利于避免多次重分配,节省时间。

// 优化前: 522ms
vector a;
for (int i = 0; i < 1e8; i++)
    a.push_back(i);
// 优化后: 259ms
vector a(1e8);
for (int i = 0; i < a.size(); i++)
    a[i] = i;
当心 size_t 溢出

size_t类型范围与编译器位数有关

vector 获取长度的方法 .size() 返回值类型为 size_t,通常 OJ 平台使用的是 32 位编译器(有些平台例如 cf 可选 64 位),那么该类型范围为 [0,232).

vector a(65536);
long long a = a.size() * a.size(); // 直接溢出变成0了

常用vector总结

v.push_back(1) 存入1
v.size() 动态数组v中的元素个数
vector遍历 for(int i=0;i
auto it=find(v.begin(),v.end(),x); 查找第一次出现元素x的迭代器
auto it=find(v.begin(),v.end(),x)-v.begin(); 查找第一次出现元素x的下标,此时it不是指针而是下标,是个int
v.earse(it);

删除指针迭代器it的空间

常用于先find找到元素再删除

2.3 栈 stack

#include

通过二次封装双端队列 (deque) 容器,实现先进后出的栈数据结构。

2.3.1 常用方法

作用 用法 示例
构造 stack<类型> stk stack stk;
进栈 .push(元素) stk.push(1);
出栈 .pop() stk.pop();
取栈顶 .top() int a = stk.top();
查看大小 / 清空 / 判空 .size()/.empty()/无清空

2.3.2 适用情形

如果不卡常的话,就可以直接用它而不需要手写栈了。

另外,vector 也可以当栈用,vector 的 .back() 取尾部元素,就相当于取栈顶,.push_back() 相当于进栈,.pop_back() 相当于出栈。

2.3.3 注意事项

<

你可能感兴趣的:(c++,算法,开发语言)