作业介绍
STL 容器
stack

queue

pair
pair是一个容器,可以存储两个不同类型的值。例如,pair<int, string> a可以存储一个整数和一个字符串。可以简单理解为系统自带的两个元素的结构体。- 获取元素一:
a.first,获取元素二:a.second。 pair已经实现了默认的比较方式,即两个pair比较先按照first优先,first相同比second。- 因此
pair类型可以直接使用sort函数。(当需要按照 first 优先比较的时候)
pair<int, int> a[N];
for (int i = 1; i <= n; i++)
{
cin >> a[i].first >> a[i].second;
}
sort(a + 1, a + n + 1); // 直接按 first 优先从小到大排序
sort(a + 1, a + n + 1, greater<>()); // 按照 first 优先从大到小排序
array
array是一个数组容器。例如,array<int, 3> a相当于一个大小为 的int数组,其元素分别为 。array已经实现了默认的比较方式,即两个array比较先按照下标为 的优先,下标为 的相同的继续向后比,以此类推。array比pair更适用于多个元素的情况,但array要求所有元素类型必须一致。
array<int, 3> a[N];
for (int i = 1; i <= n; i++)
{
cin >> a[i][0] >> a[i][1] >> a[i][2];
}
sort(a + 1, a + n + 1);
sort(a + 1, a + n + 1, greater<>());
总结
是否有自带的支持超过 个以上元素且元素类型可以不同的容器?
答:tuple(元组),感兴趣可以自学。或者选择 pair 套 pair。例 pair<int, pair<char, bool>>
map
概述
map 是有序键值对容器,它的元素的键是唯一的。查找、删除和插入操作拥有对数复杂度()。map 通常实现为 。
定义:map<键, 值> 变量名。其中键和值写对应的元素类型即可。例如:
map<int, int> mp。定义一个键和值都是int类型的map。map<string, int> mp。定义一个键是string,值是int类型的map。map<vector<int>, int> mp。定义一个键是vector<int>,值是int类型的map。map<int, vector<int>> mp。定义一个键是int,值是vector<int>类型的map。map<int, map<int, int>> mp。定义一个键是int,值是map<int, int>类型的map。
注意键必须是支持比较的类型。若使用自定义的结构体类型时,还需要自定义比较规则传入 map。
基础使用
以 map<int, int> mp 为例,设 为 map 里存储的元素个数。
- 修改(创建):和数组用法类似,执行
mp[x] = y。只要 和 均在int范围内即可。复杂度 - 查找(查找键):使用
count函数,mp.count(x)。返回值为true说明存在键 ,否则不存在。复杂度 - 删除(删除键):使用
erase函数,mp.erase(x)。,复杂度 - 键的个数:使用
size函数。mp.size()可以求出存了几个键(几个键值对)。 - 清空
map:使用函数clear完成mp.clear(),可以清除 map 的所有键值对。
map 的遍历
以 map<int, int> mp 为例。
法一
使用迭代器遍历。首先 map<int, int> iterator:: it。创建一个名为 it 的 map<int, int> 的迭代器。
map<int, int> iterator:: it;
for (it = mp.begin(); it != mp.end(); ++it)
{
// 键是 it->first,值是 it->second
cout << it->first << " " << it->second << "\n";
}
-> 运算符: -> 是一个成员访问运算符。对于迭代器,它用于访问迭代器所指向的元素的成员。
map 的键值对是一个 pair 对象,当我们使用迭代器遍历时,需要使用 it->first 和 it->second 分别获取键和值。
法二
使用 auto 遍历。语法简单且推荐。
for (auto it : mp)
{
// 键是 it.first,值是 it.second
cout << it.first << " " << it.second << "\n";
}
应用场景
通俗理解 map 就是一个下标是任意类型的 ,通过以下例子体会 map 的使用场景。
- 输入 个数字 ,请统计每个数字的出现次数。()
答: 简单,开一个大小为 的数组 cnt,执行 cnt[x]++ 即可。
- 输入 个数字 ,请统计每个数字的出现次数。(,)
答:开大小为 的数组通常会 MLE。主要是由于只存储 个数字,但数值范围过大,有很多位置根本不需要。如何解决?
定义 map<int, int> cnt 即可,如果存储 long long 范围内的数字就改为 map<long long, int> cnt。
- 输入 个字符串 ,请统计每个字符串的出现次数。
答:定义 map<string, int> cnt 即可。
算法函数
由于 map 自动按照键排序,因此支持一些算法函数。
以 map<int, int> mp 为例。
lower_bound(x): 返回指向刚好大于或等于 的 。
mp.lower_bound(x)。注意和 vector 和数组的使用方式区分。
返回值是迭代器,不存在返回 mp.end()。
auto it = mp.lower_bound(x);
if (it != mp.end())
{
cout << it->first << " " << it->second;
}
upper_bound(x): 返回指向刚好大于 的 。用法同上
二维 map
- 方式一:
map<int, int> mp[100005]。每一个mp[i]都是一个 map。例如:mp[i][j] = k。
$\textcolor{red}{mp[i] 指的是第 i 个 map,第 i 个 map 创建了一个键为j 其值是 k。}$
- 方式二:定义
map<int, map<int, int>> mp即可。 $\textcolor{red}{键是 int,其对应的值又是一个 map,相当于是一个二维的 map}$
$\textcolor{red}{mp[i] 指的是键为 i,其对应的值又是一个 map,在值这个 map 里,键是 j,值是 k。}$
unordered_map
unordered_map是C++标准库(STL)中的一个关联容器,用于存储键值对。它基于哈希实现,。它的大部分操作最好情况下的时间复杂度是常数级别的,但最坏情况下都是 。(产生哈希冲突)
其大部分操作和 map 相同,但由于键不排序所以无法使用二分函数。
以下操作 复杂度为常数级别, 为 。
以 unordered_map<int, int> mp 为例。
- 创建或赋值:
mp[x] = y,平均复杂度为 ,最坏复杂度为 。 - 删除
erase:mp.erase(x),删除键 ,复杂度同上。 - 查找键
count:mp.count(x),判断键是否存在,复杂度同上。 - 其他函数:
size(键的个数),clear(清空)等。
multimap
它和 map 的区别在于:map 的键是唯一的,而 multimap 键是可以重复的。即可以储存更多的信息。因此操作函数会有一些差别。
由于键依然排序,所以复杂度还是 级别的。
insert:插入键值对函数,例如mp.insert({1, 3}),插入键是 值是 。不支持像map一样的赋值操作。find:查找键 的位置,返回值为迭代器。erase:删除 键 或 删除迭代器。由于键可以重复,若传入键会删除所有的键,用时需谨慎。count:统计键的个数。- 支持二分函数,
lower_bound和upper_bound。
总结
map 就像是一个下标可以是任意类型的数组。掌握好 map 的使用很多题做起来都游刃有余。
set
概述
set 是一个关联式容器。其内部元素自动排序且去重(默认升序)。搜索、移除和插入拥有 级别的复杂度。
set<类型名> 变量名。
set<int> s, set<long long> sset<string> s, set<pair<int, int>> s
操作函数
以 set<int> s 为例。
s.insert(x)当容器中没有等价元素的时候,将元素 插入到set中。时间复杂度s.erase(x)删除值为 的元素。时间复杂度s.erase(pos)删除迭代器为 的元素,要求迭代器必须存在,否则RE。时间复杂度s.erase(first,last)删除迭代器在 范围内的所有元素。(不包括迭代器last)s.clear()清空set。
注意一些和迭代器有关的操作先判断是否存在该迭代器在操作,例如 s.erase(s.begin()) 相当于删除集合的最小值。若集合为空这是一个会造成 RE 的操作。
其余函数和技巧
find函数,s.find(x)判断集合里是否存在 ,返回值为迭代器,不存在返回s.end()。时间复杂度lower_bound函数,s.lower_bound(x)找到集合里首个大于或等于元素 的迭代器,不存在返回s.end()。upper_bound同上,找到首个大于 的迭代器。- 获取最小值:
auto it = s.begin()。
注意 it 是一个迭代器。通过 *it 解引用获取迭代器对应的数值。
- 获取最大值:
auto it = s.rbegin(),利用rbegin逆迭代器即可。
注意一些和迭代器有关的操作先判断是否存在该迭代器在操作,例如 s.erase(s.begin()) 相当于删除集合的最小值。若集合为空这是一个会造成 RE 的操作。
multiset
multiset 是一个关联式容器。其内部元素自动排序(默认升序)。搜索、移除和插入拥有 级别的复杂度。
multiset<类型名> 变量名。下面以 multiset<int> s 为例。
- 插入和二分等函数都没有区别。
- 注意删除函数的差异。
按值删除:s.erase(x),会删除所有的 。
按迭代器删除:只会删除迭代器这个位置的元素。
auto it = s.find(x); // 找到第一个 x 的迭代器
if (it != s.end()) s.erase(it); // 不存在别删除
其它类型的 set
unordered_set:无序集合,元素去重但不排序。竞赛中不常用。unordered_multiset:无序可重集合,元素不去重也不排序。竞赛中不常用。
STL课件
题目
- 状态
- 正在进行…
- 题目
- 11
- 开始时间
- 2025-8-17 0:00
- 截止时间
- 2026-8-5 22:00
- 可延期
- 24 小时