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 键值映射

这三个需求正好对应三段学习:先学会用容器存数据,再学会用算法处理数据,最后用关联容器按键整理数据。

学习方法:先预测,再对照

读本课代码时,建议固定用三步:

  1. 先预测:看完整段代码,用自己的话推一遍“程序会输出什么”,先写在纸上或心里。
  2. 再运行:照着前面的编译命令跑一遍,把真实输出和你的预测对比。
  3. 对不上就查:输出和预测不同时,别急着改代码,先找出是哪个位置、哪一步的变量和你以为的不一样。页面里的「一步步看变化」表就是干这个用的。

后面每一页都配有「动手检查」:一道预测输出、一道修改代码。它们比示例更重要——能预测、能改动,才算真的会了。

动手检查:选择自测

先自己判断,再展开折叠核对。

  1. 只想把一组长度不定的数按输入顺序存下来,用哪种容器?
  2. 想按姓名统计每个名字出现了几次,用哪种容器?
  3. 想把这组数从小到大输出,用哪个算法?
参考结果与解释
  1. vector:长度可变、按顺序保存、可按下标访问,正合适。见 vector。
  2. map:键是姓名,值是次数;读到一个名字就 cnt[name]++,最后遍历输出。见 map。
  3. sort:给它一段区间,默认按从小到大排好。见 sort。

关于练习

本页是课程入口,负责讲“学什么、按什么顺序学、怎么验证”,所以不安排 OJ 题目。等你读完 vector 和 sort 之后,每一页的「立即练习」里都有配套题目可做。