STL主要包括容器、算法、迭代器、函数
在一般情形下挑选适合的stl进行coding可以极大的提高coding效率
但是针对一些个别的题目,需要手敲的数据结构与算法,stl的效率比不上针对特定情况下的手动的数据结构,要具体情况具体分析
vector(动态数组)
理解为可调整大小的动态数组即可
基本语法
vector<数据类型> arr(数组长度, 内容)
初始化
| 操作方式 | 说明 | 示例 |
|---|---|---|
| 默认构造 | 创建空 vector | vector<int> v; |
| 带大小构造 | 创建含 n 个默认初始化元素的 vector |
vector<int> v(5);(5 个 0) |
| 带大小和初始值 | 创建含 n 个 val 的 vector |
vector<int> v(5, 10);(5 个 10) |
| 拷贝构造 | 复制另一个 vector | vector<int> v2(v1); 或 vector<int> v2 = v1; |
一维数组:
vector<int> a; //初始化一个数组
vector<int> b(10); //初始化一个长度为10的数组
vector<int> c(10, 0); //初始化一个长度为10,全部为0的数组
二维数组:
可以理解为在一维数组中每个位置存放了一个一维数组
在空间上可以用平面Oxy表示
vector<vector<int>>a(10,vector<int>()); //初始化一个10行的二维数组 列为空
vector<vector<int>>b(10,vector<int>(10,0)); //初始化一个10行10列 值全为0的数组
三维数组:
可以理解为在二维数组中每个位置存放了一个一维数组
在空间上可以用三维空间Oxyz表示
vector<vector<vector<int>>>a(10,vector<vector<int>>());//初始化一个10行0列0高数组
vector<vector<vector<int>>>b(10,vector<vector<int>>(10,vector<int>()));//初始化一个10行10列0高的数组
vector<vector<vector<int>>>c(10,vector<vector<int>>(10,vector<int>(10,0)));////初始化一个10行10列10高的数组
数组复制:
vector<int>b(a)//把数组a复制到b
访问
| 操作 | 说明 | 注意事项 |
|---|---|---|
at() |
带边界检查的访问(如 v.at(i)) |
越界时抛出 std::out_of_range 异常 |
front() |
获取第一个元素 | 空容器调用未定义 |
back() |
获取最后一个元素 | 空容器调用未定义 |
vector<int> v = {10, 20, 30, 40};
cout << v[1] << endl; // 20下标访问
cout << v.front() << endl;// 10首元素访问
cout << v.back() << endl; // 40尾元素访问
迭代器
| 迭代器类型 | 说明 |
|---|---|
begin() / end() |
正向迭代器(begin 指向首元素,end 指向尾后位置) |
rbegin() / rend() |
反向迭代器(rbegin 指向尾元素,rend 指向首前位置) |
rbegin和rend有一个比较容易理解的例子
当你向数组输入1>>2>>3时,数组实际上是[3,2,1]
vector<int> v = {1, 2, 3, 4, 5};
// 正向遍历
for (auto it = v.begin(); it != v.end(); ++it) {
cout << *it << " "; // 输出 1 2 3 4 5
}
// 反向遍历
for (auto it = v.rbegin(); it != v.rend(); ++it) {
cout << *it << " "; // 输出 5 4 3 2 1
}
容量与大小
| 操作 | 说明 |
|---|---|
size() |
返回当前元素个数 |
empty() |
判断是否为空(size() == 0) |
capacity() |
返回预分配的容量(capacity() >= size()) |
reserve(n) |
预分配至少 n 的容量(若 n > capacity 则扩容,否则无操作) |
resize(n) |
调整元素个数为 n:- 若 n > size,默认初始化新元素- 若 n < size,删除末尾元素 |
resize(n, val) |
调整大小,新元素用 val 初始化 |
元素的增删改
| 操作 | 说明 |
|---|---|
push_back(val) |
末尾添加元素(拷贝 / 移动 val) |
emplace_back(args...)(C++11) |
末尾直接构造 元素(args 为构造函数参数,比 push_back 高效) |
pop_back() |
删除末尾元素(空容器调用未定义) |
insert(pos, val) |
在迭代器 pos 前插入 val,返回新元素的迭代器 |
insert(pos, n, val) |
在 pos 前插入 n 个 val |
insert(pos, begin, end) |
在 pos 前插入迭代器范围 [begin, end) 的元素 |
erase(pos) |
删除迭代器 pos 指向的元素,返回下一个元素的迭代器 |
erase(begin, end) |
删除范围 [begin, end) 的元素,返回 end |
clear() |
清空所有元素(size 变为 0,capacity 不变) |
vector<int> v = {1, 2, 3};
v.push_back(4); // 末尾添加 4 → [1,2,3,4]
v.emplace_back(5); // 末尾直接构造 5 → [1,2,3,4,5]
v.pop_back(); // 删除末尾 → [1,2,3,4]
auto it = v.insert(v.begin()+2, 10); // 在索引 2 前插入 10 → [1,2,10,3,4]
v.erase(v.begin()); // 删除首元素 → [2,10,3,4]
v.clear(); // 清空
stack(栈)
stack底层容器是deque,也可以用数组实现
初始化
| 操作 | 说明 | 代码示例 |
|---|---|---|
| 默认构造 | 创建空栈 | stack<int> st; |
| 拷贝构造 | 复制一个栈 | stack<int> st2(st1); |
| 自定义底层容器 | 指定用 vector/list 实现 | stack<int, vector<int>> st; |
基本操作
入栈
stack<int> st;
st.push(10); // 栈:[10]
st.push(20); // 栈:[10, 20](20 是栈顶)
出栈
st.pop(); // 删除 20 → 栈:[10]
返回栈顶元素
cout << st.top(); // 输出 10
st.top() = 100; // 修改栈顶为 100
判断栈为空
if (st.empty()) {
cout << "栈为空";
}
返回元素个数
cout << st.size(); // 输出当前元素个数
queue(队列)
初始化
| 写法 | 说明 |
|---|---|
queue<int> q; |
空队列 |
queue<int> q2(q1); |
拷贝构造 |
queue<int, list<int>> q; |
指定底层为 list |
基本操作
入队
q.push(10);
q.push(20);
q.push(30);
// 队列:10(队头)→20→30(队尾)
出队
q.pop(); // 删除 10
队头获取
cout << q.front(); // 20
q.front() = 200;
队尾获取
cout << q.back(); // 30
判断空与元素个数
if (q.empty())
cout << q.size();
deque(双端队列)
初始化
| 操作 | 说明 | 代码示例 |
|---|---|---|
| 默认构造 | 空 deque | deque<int> dq; |
| 大小构造 | n 个默认值 | deque<int> dq(5); |
| 大小 + 初始值 | n 个 val | deque<int> dq(5, 10); |
| 拷贝构造 | 复制另一个 deque | deque<int> dq2(dq1); |
访问
| 操作 | 说明 |
|---|---|
dq.front() |
访问第一个元素 |
dq.back() |
访问最后一个元素 |
deque<int> dq = {10,20,30};
cout << dq[0]; // 10
cout << dq.front(); // 10
cout << dq.back(); // 30
迭代器与vector一样
| 操作 | 说明 |
|---|---|
begin() / end() |
正向迭代器 |
rbegin() / rend() |
反向迭代器 |
容量与大小
| 操作 | 说明 |
|---|---|
size() |
元素个数 |
empty() |
是否为空 |
resize(n) |
调整大小,多删少补(默认 0) |
resize(n, val) |
新元素用 val 填充 |
list(链表)
初始化
| 操作 | 说明 | 代码示例 |
|---|---|---|
| 默认构造 | 空 list | list<int> lt; |
| 带大小构造 | 创建含 n 个默认初始化元素的 list |
list<int> lt(5);(5 个 0) |
| 带大小和初始值 | 创建含 n 个 val 的 list |
list<int> lt(5, 10);(5 个 10) |
| 拷贝构造 | 复制另一个 list | list<int> lt2(lt1); 或 list<int> lt2 = lt1; |
访问
链表不支持随机访问
| 操作 | 说明 | 注意事项 |
|---|---|---|
front() |
获取第一个元素 | 空容器调用未定义 |
back() |
获取最后一个元素 | 空容器调用未定义 |
list<int> lt = {10, 20, 30};
cout << lt.front() << endl; // 10(首元素)
cout << lt.back() << endl; // 30(尾元素)
迭代器
| 迭代器类型 | 说明 |
|---|---|
begin() / end() |
正向迭代器(begin 指向首元素,end 指向尾后位置) |
rbegin() / rend() |
反向迭代器(rbegin 指向尾元素,rend 指向首前位置) |
容量与大小
| 操作 | 说明 |
|---|---|
size() |
返回当前元素个数 |
empty() |
判断是否为空(size() == 0) |
resize(n) |
调整元素个数为 n:- 若 n > size,默认初始化新元素- 若 n < size,删除末尾元素 |
resize(n, val) |
调整大小,新元素用 val 初始化 |
增删改
list<int> lt = {1, 2, 3};
lt.push_back(4); // 尾插 → [1,2,3,4]
lt.push_front(0); // 头插 → [0,1,2,3,4]
lt.pop_back(); // 尾删 → [0,1,2,3]
lt.pop_front(); // 头删 → [1,2,3]
list<int> lt = {1, 2, 3};
auto it = next(lt.begin(), 1); // 获取指向第2个元素(2)的迭代器
lt.insert(it, 10); // 在 it 前插入 10 → [1,10,2,3]
lt.erase(it); // 删除 it 指向的元素(2)→ [1,10,3]
list<int> lt1 = {1, 2, 3};
list<int> lt2 = {4, 5, 6};
auto it = next(lt1.begin(), 1); // lt1 中指向 2 的迭代器
lt1.splice(it, lt2); // 将 lt2 全部元素移动到 lt1 的 it 前
// lt1: [1,4,5,6,2,3],lt2 变为空
list<int> lt = {1, 2, 2, 3, 4, 2};
lt.remove(2); // 删除所有 2 → [1,3,4]
lt.remove_if([](int x) { return x > 3; }); // 删除大于 3 的元素 → [1,3]
list<int> lt = {1, 2, 2, 3, 3, 3, 4};
lt.unique(); // 去重 → [1,2,3,4]
list<int> lt = {3, 1, 4, 1, 5, 9};
lt.sort(); // 升序 → [1,1,3,4,5,9]
lt.sort(greater<int>()); // 降序 → [9,5,4,3,1,1]
lt.clear(); // 清空所有元素,size 变为 0
priority_queue(优先队列/堆)
初始化
| 操作 | 说明 | 代码示例 |
|---|---|---|
| 默认构造 | 空优先队列(默认大顶堆,底层 vector) | priority_queue<int> pq; |
| 自定义比较函数 | 指定优先级规则(如小顶堆) | priority_queue<int, vector<int>, greater<int>> pq; |
| 自定义底层容器 | 用 deque 作为底层 |
priority_queue<int, deque<int>> pq; |
主要操作
入队、出队、返回堆顶元素、返回队列大小、判空
priority_queue<int> pq;
pq.push(10);
pq.push(30);
pq.push(20);
// 堆结构:30(堆顶)→20→10(默认大顶堆)
pq.pop(); // 删除堆顶 30,新堆顶为 20
cout << pq.top(); // 输出 20
pq.top() = 200; // 修改堆顶为 200(修改后需注意堆性质可能被破坏,不建议直接修改)
if (pq.empty()) {
cout << "队列为空";
}
cout << pq.size();
自定义优先级
自定义优先队列的排序算法
主要有两种
一种是重载运算符
#include <iostream>
#include <queue>
#include <string>
using namespace std;
// 自定义类:学生,按成绩排序
struct Student {
string name;
int score;
// 重载 < 运算符:默认大顶堆(成绩高的优先)
bool operator<(const Student& other) const {
return score < other.score; // 注意:大顶堆用 <,小顶堆用 >
}
};
int main() {
priority_queue<Student> pq;
pq.push({"Alice", 85});
pq.push({"Bob", 95});
pq.push({"Charlie", 90});
// 堆顶:Bob(95)
cout << pq.top().name << " " << pq.top().score << endl; // Bob 95
return 0;
}
一种是自定义函数对象
#include <iostream>
#include <queue>
#include <string>
using namespace std;
struct Student {
string name;
int score;
};
// 自定义函数对象:小顶堆(成绩低的优先)
struct CompareScore {
bool operator()(const Student& a, const Student& b) const {
return a.score > b.score; // 小顶堆用 >
}
};
int main() {
// 声明:底层 vector,比较函数 CompareScore
priority_queue<Student, vector<Student>, CompareScore> pq;
pq.push({"Alice", 85});
pq.push({"Bob", 95});
pq.push({"Charlie", 90});
// 堆顶:Alice(85)
cout << pq.top().name << " " << pq.top().score << endl; // Alice 85
return 0;
}
map(表)
map自带排序
注意multimap是可以多个键对应一个值
unordered_map则是不带自排序的
初始化
| 操作 | 说明 | 代码示例 |
|---|---|---|
| 默认构造 | 空 map(默认升序,键类型需支持 < 比较) |
map<int, string> m; |
| 自定义比较函数 | 指定排序规则(如降序) | map<int, string, greater<int>> m; |
| 拷贝构造 | 复制另一个 map | map<int, string> m2(m1); 或 map<int, string> m2 = m1; |
| 迭代器范围构造 | 从其他容器的迭代器范围初始化 | map<int, string> m(m1.begin(), m1.end()); |
可用下标访问
迭代器同vector
容量与大小操作也同上
元素插入
| 操作 | 说明 | 返回值 |
|---|---|---|
insert(pair) |
插入键值对 pair |
std::pair<iterator, bool>:- iterator 指向插入位置(或已存在的元素)- bool 表示是否插入成功(true 成功,false 键已存在) |
insert(make_pair(key, value)) |
用 std::make_pair 构造键值对插入 |
同上 |
元素查找
| 操作 | 说明 | 返回值 |
|---|---|---|
find(key) |
查找键为 key 的元素 |
若找到,返回指向该元素的迭代器;否则返回 end() |
count(key) |
统计键为 key 的元素个数 |
0 或 1(因为键唯一,用于判断键是否存在) |
lower_bound(key) |
查找第一个不小于 key 的元素 |
指向该元素的迭代器;若所有元素都小于 key,返回 end() |
upper_bound(key) |
查找第一个大于 key 的元素 |
指向该元素的迭代器;若所有元素都不大于 key,返回 end() |
equal_range(key) |
查找键为 key 的元素范围 |
std::pair<lower_bound(key), upper_bound(key)>(因键唯一,两个迭代器要么相同,要么指向相邻位置) |
map<int, string> m = {{1, "one"}, {3, "three"}, {5, "five"}};
// 1. find 查找
auto it = m.find(3);
if (it != m.end()) {
cout << it->second << endl; // "three"
}
// 2. count 判断存在
if (m.count(5)) {
cout << "键 5 存在" << endl;
}
// 3. lower_bound 和 upper_bound
auto low = m.lower_bound(2); // 第一个不小于 2 的是 3
auto up = m.upper_bound(4); // 第一个大于 4 的是 5
cout << low->first << endl; // 3
cout << up->first << endl; // 5
// 4. equal_range
auto range = m.equal_range(3);
if (range.first != range.second) {
cout << range.first->second << endl; // "three"
}
set(集合)
multi和unordered用法和map差不多
注意set不能用下标访问
初始化
| 操作 | 说明 | 代码示例 |
|---|---|---|
| 默认构造 | 空 set(默认升序,元素类型需支持 < 比较) |
set<int> s; |
| 自定义比较函数 | 指定排序规则(如降序) | set<int, greater<int>> s; |
| 拷贝构造 | 复制另一个 set | set<int> s2(s1); 或 set<int> s2 = s1; |
| 迭代器范围构造 | 从其他容器的迭代器范围初始化(自动去重) | set<int> s(v.begin(), v.end()); |
其他操作都跟map差不多
string(字符串)
熟悉的字符串
初始化
| 操作 | 说明 | 代码示例 |
|---|---|---|
| 默认构造 | 空字符串 | string s; |
| 带大小和字符 | 创建含 n 个 c 的字符串 |
string s(5, 'a');("aaaaa") |
| 拷贝构造 | 复制另一个 string | string s2(s1); 或 string s2 = s1; |
| 子串构造 | 从 s1 的 pos 位置开始,取 count 个字符(count 省略则到末尾) |
string s(s1, 2, 3);(从索引 2 取 3 个) |
| 迭代器范围构造 | 从迭代器范围 [begin, end) 初始化 |
string s(s1.begin(), s1.end()); |
元素访问
| 操作 | 说明 | 注意事项 |
|---|---|---|
s[i] |
下标访问(从 0 开始) | 不检查越界,越界行为未定义 |
s.at(i) |
带边界检查的访问 | 越界时抛出 std::out_of_range 异常 |
s.front() |
访问第一个字符(s[0]) |
空字符串调用未定义 |
s.back() |
访问最后一个字符(s[s.size()-1]) |
空字符串调用未定义 |
s.data() |
返回指向底层字符数组的指针 | C++17 前为 const char*,C++17 起为 char*(可写) |
s.c_str() |
返回指向底层字符数组的 const char*(以 \0 结尾) |
始终为 const,用于与 C 风格接口交互 |
string s = "hello";
cout << s[0] << endl; // 'h'(下标访问)
cout << s.front() << endl; // 'h'
cout << s.back() << endl; // 'o'
迭代器同之前的
容量与大小也同之前的
字符串的修改
| 操作 | 说明 |
|---|---|
s.push_back(c) |
末尾添加字符 c |
s.pop_back() |
删除末尾字符(空字符串调用未定义) |
字符串可赋值操作
| 操作 | 说明 |
|---|---|
s += s2 / s += "str" / s += c |
追加 string、C 字符串或字符 |
s.append(s2) |
追加 string s2 |
s.append(s2, pos, count) |
追加 s2 从 pos 开始的 count 个字符 |
s.append("str") |
追加 C 字符串 |
s.append("str", n) |
追加 C 字符串的前 n 个字符 |
s.append(n, c) |
追加 n 个字符 c |
s.append(begin, end) |
追加迭代器范围 [begin, end) 的字符 |
插入
| 操作 | 说明 |
|---|---|
s.insert(pos, s2) |
在 pos 位置插入 string s2 |
s.insert(pos, "str") |
在 pos 位置插入 C 字符串 |
s.insert(pos, n, c) |
在 pos 位置插入 n 个字符 c |
s.insert(iterator, c) |
在迭代器 iterator 前插入字符 c,返回指向新字符的迭代器 |
s.insert(iterator, n, c) |
在迭代器前插入 n 个字符 c |
s.insert(iterator, begin, end) |
在迭代器前插入迭代器范围 [begin, end) 的字符 |
删除
| 操作 | 说明 |
|---|---|
s.erase(pos, count) |
从 pos 位置开始删除 count 个字符(count 省略则删除到末尾) |
s.erase(iterator) |
删除迭代器指向的字符,返回指向下一个字符的迭代器 |
s.erase(begin, end) |
删除迭代器范围 [begin, end) 的字符,返回 end |
s.clear() |
清空所有字符(size 变为 0,capacity 不变) |
替换
| 操作 | 说明 |
|---|---|
s.replace(pos, count, s2) |
从 pos 开始的 count 个字符替换为 s2 |
s.replace(pos, count, "str") |
替换为 C 字符串 |
s.replace(pos, count, n, c) |
替换为 n 个字符 c |
s.replace(begin, end, s2) |
替换迭代器范围 [begin, end) 的字符为 s2 |
查找
| 操作 | 说明 |
|---|---|
s.find(s2, pos=0) |
从 pos 开始正向 查找 string s2,返回首次出现的索引 |
s.find("str", pos=0) |
查找 C 字符串 |
s.find(c, pos=0) |
查找字符 c |
s.rfind(s2, pos=npos) |
从 pos 开始反向查找(从后往前),返回最后一次出现的索引 |
s.find_first_of(s2, pos=0) |
从 pos 开始查找 s2 中任意字符首次出现的索引 |
s.find_last_of(s2, pos=npos) |
从 pos 开始反向查找 s2 中任意字符最后一次出现的索引 |
s.find_first_not_of(s2, pos=0) |
从 pos 开始查找不在 s2 中的字符首次出现的索引 |
s.find_last_not_of(s2, pos=npos) |
从 pos 开始反向查找不在 s2 中的字符最后一次出现的索引 |
比较
| 操作 | 说明 | 返回值 |
|---|---|---|
s.compare(s2) |
比较 s 和 s2 |
- <0:s 字典序小于 s2- =0:相等- >0:s 字典序大于 s2 |
s.compare(pos, count, s2) |
比较 s 从 pos 开始的 count 个字符与 s2 |
同上 |
s.compare(pos, count, s2, pos2, count2) |
比较 s 的子串与 s2 的子串 |
同上 |
子串操作
| 操作 | 说明 |
|---|---|
s.substr(pos=0, count=npos) |
返回从 pos 开始的 count 个字符组成的子串(count 省略则到末尾) |
类型修改
| 操作 | 说明 | 异常 |
|---|---|---|
stoi(s, pos=nullptr, base=10) |
转 int(pos 用于存储转换后未处理的第一个字符索引,base 为进制) |
转换失败抛 std::invalid_argument,溢出抛 std::out_of_range |
stol(s, pos=nullptr, base=10) |
转 long |
同上 |
stoll(s, pos=nullptr, base=10) |
转 long long |
同上 |
stoul(s, pos=nullptr, base=10) |
转 unsigned long |
同上 |
stoull(s, pos=nullptr, base=10) |
转 unsigned long long |
同上 |
stof(s, pos=nullptr) |
转 float |
同上 |
stod(s, pos=nullptr) |
转 double |
同上 |
stold(s, pos=nullptr) |
转 long double |
同上 |
举例
#include <iostream>
#include <string>
using namespace std;
int main() {
// 1. 初始化
string s = "hello world";
// 2. 元素访问
cout << s[0] << " " << s.at(1) << endl; // h e
cout << s.front() << " " << s.back() << endl; // h d
// 3. 修改操作
s += "!"; // "hello world!"
s.append(" 123", 3); // "hello world! 123"
s.insert(5, " C++"); // "hello C++ world! 123"
s.erase(5, 4); // "hello world! 123"
s.replace(6, 5, "C++"); // "hello C++! 123"
// 4. 查找操作
size_t pos = s.find("C++");
if (pos != string::npos) {
cout << "找到 C++,索引:" << pos << endl; // 6
}
// 5. 子串
string sub = s.substr(6, 3); // "C++"
cout << "子串:" << sub << endl;
// 6. 比较
string s2 = "hello C++!";
cout << (s == s2) << endl; // 0(s 还有 " 123")
// 7. 类型转换
s = "456";
int num = stoi(s); // 456
s = to_string(789); // "789"
// 8. 遍历
for (char c : s) {
cout << c << " "; // 7 8 9
}
return 0;
}