C++ 竞赛入门
STL 学习指南
23 篇的学习路线、编译运行方式,以及“先预测、再运行”的验证方法。
STL 学习指南
读完能做什么
- 能说清这本书的 STL 部分覆盖什么、不覆盖什么,知道从哪里开始。
- 能照着页面里的编译运行方式,把示例复制到本机跑起来。
- 能对照学习路线表,找到下一个该读的文章。
- 能说出容器、迭代器、算法三者的关系,并用它们做一次“从需求到文章”的定位。
为什么需要它
STL 的内容很多:容器就有七八种,算法几十个。如果一上来就按字母顺序一个个背接口,很容易看完就忘,也不知道什么时候该用哪个。
这份指南解决的是顺序问题:先读什么、后读什么,每一课解决什么问题。按路线走一遍,你会先用 vector 建立对容器的具体感觉,再理解迭代器,然后才学算法和各种容器,最后用一张“需求 → 工具”的对照表收尾。
STL 在本书里学什么
**读者基础:**本课假设你已经学过变量、循环、函数和数组,能用 cin / cout 读写数据。如果这些还不熟,建议先把基础篇过一遍再回来。
本书的 STL 部分共 23 篇,覆盖竞赛入门最常用的容器与算法:
- 序列容器:
vector、deque、list - 容器适配器:
stack、queue、priority_queue - 关联容器:
set、map、multimap - 常用工具:
string、pair、bitset - 常用算法:
find、sort、二分查找、unique、nth_element
需要说明:string、pair 严格说属于通用的标准库工具,不是“STL 容器”这个狭义概念的一部分,但因为竞赛里天天用,本书把它们一起纳入。另外,STL 并不等于“整个 C++ 标准库”——输入输出、数学函数等很多内容不在本课范围内。
怎么编译和运行
本课代码统一使用 GNU C++17。把示例保存成 main.cpp,在终端里执行:
g++ -std=c++17 -Wall -Wextra main.cpp -o main
./main
-std=c++17 指定语言标准,-Wall -Wextra 让编译器把可疑写法都提醒出来。下面是一个可以直接跑的最小例子:
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> score = {80, 60, 90, 70};
sort(score.begin(), score.end());
cout << score.size() << " 个成绩,最小的是 " << score.front() << '\n';
return 0;
}
输出:
4 个成绩,最小的是 60
这个例子的详细解释在下一课什么是 STL里。本机用 GCC 16.2.0 验证,命令是 g++-16 -std=c++17 -Wall -Wextra main.cpp -o main;如果你机器上的 g++ 是别的版本,-std=c++17 这一项要保留。
学习路线:23 篇的顺序
按下表从上往下读。前 4 篇打基础,后面按“容器 → 算法 → 总结”展开。
| 编号 | 主题 | 文章 |
|---|---|---|
| 01 | 课程入口 | 本页 |
| 02 | 从一个具体问题认识 STL | 什么是 STL |
| 03 | 序列容器 | vector 动态数组 |
| 04 | 迭代器与区间基础 | 容器、迭代器与区间 |
| 05 | 字符串 | string 字符串 |
| 06 | 键值对 | pair 二元组 |
| 07 | 序列容器 | deque 双端队列 |
| 08 | 序列容器 | list 链表 |
| 09 | 容器适配器 | stack 栈 |
| 10 | 容器适配器 | queue 队列 |
| 11 | 算法入口 | STL 算法 |
| 12 | 比较规则 | 比较规则与函数对象 |
| 13 | 容器适配器 | priority_queue 优先队列 |
| 14 | 关联容器 | set 有序集合 |
| 15 | 关联容器 | map 键值映射 |
| 16 | 关联容器 | multimap 一键多值 |
| 17 | 算法 | find 查找 |
| 18 | 算法 | sort 排序 |
| 19 | 算法 | 二分查找 |
| 20 | 算法 | unique 去重 |
| 21 | 算法 | nth_element 第 k 小 |
| 22 | 位集 | bitset 位集 |
| 23 | 总结 | STL 总结 |
容器、迭代器、算法三者的关系
整个 STL 可以看成三个角色在配合:容器负责存,迭代器负责指出位置,算法负责处理一段位置之间的数据。
graph LR
C["容器:保存数据"] -->|"begin 和 end 给出位置"| I["迭代器:表示位置"]
I -->|"first 到 last 组成一段区间"| A["算法:处理区间里的元素"]
A -->|"结果写回容器"| C
举一个具体的例子:sort(score.begin(), score.end())。score 是容器,保存成绩;score.begin() 和 score.end() 是两个迭代器,圈出一段区间;sort 是算法,把这段区间里的成绩排好。三者各自独立,正因为如此,同一个 sort 才能既排 vector 又排数组。细节见容器、迭代器与区间。
从需求找到文章
拿到一个具体需求时,先判断它属于哪一类,再去读对应文章。
| 需求 | 用到的工具 | 先读这篇 |
|---|---|---|
| 把若干成绩保存下来,长度事先不确定 | vector |
vector 动态数组 |
| 把成绩按从低到高排好 | sort |
sort 排序 |
| 按姓名统计每个人出现了几次 | map |
map 键值映射 |
这三个需求正好对应三段学习:先学会用容器存数据,再学会用算法处理数据,最后用关联容器按键整理数据。
学习方法:先预测,再对照
读本课代码时,建议固定用三步:
- 先预测:看完整段代码,用自己的话推一遍“程序会输出什么”,先写在纸上或心里。
- 再运行:照着前面的编译命令跑一遍,把真实输出和你的预测对比。
- 对不上就查:输出和预测不同时,别急着改代码,先找出是哪个位置、哪一步的变量和你以为的不一样。页面里的「一步步看变化」表就是干这个用的。
后面每一页都配有「动手检查」:一道预测输出、一道修改代码。它们比示例更重要——能预测、能改动,才算真的会了。
动手检查:选择自测
先自己判断,再展开折叠核对。
- 只想把一组长度不定的数按输入顺序存下来,用哪种容器?
- 想按姓名统计每个名字出现了几次,用哪种容器?
- 想把这组数从小到大输出,用哪个算法?
参考结果与解释
关于练习
本页是课程入口,负责讲“学什么、按什么顺序学、怎么验证”,所以不安排 OJ 题目。等你读完 vector 和 sort 之后,每一页的「立即练习」里都有配套题目可做。