Appearance
📦 06. STL 初探
一、什么是 STL?🤔
STL(Standard Template Library,标准模板库) 是 C++ 标准库的核心组成部分,它提供了一组现成的容器、算法和迭代器。
简单来说:STL 就是 C++ 给你准备好的"工具箱"。
想象一下,你要造一个书架:
- 没有工具箱:你得自己锯木头、自己炼铁做钉子、自己磨刨子……
- 有了工具箱:直接从盒子里拿出电锯、钉枪、刨子,开工!
STL 就是这个"工具箱"——别人已经写好了最高效的数据结构和算法,你直接拿来用就行。
为什么要学 STL?
| 手写 | 使用 STL |
|---|---|
| 自己写排序,可能 bug 一堆 | sort(arr, arr+n) 一行搞定 |
| 自己写动态数组,容易内存泄漏 | vector<int> v 自动管理内存 |
| 手动复制字符串,麻烦 | string s = "hello" 直接赋值 |
| 自己写链表,各种指针绕晕 | list<int> l 双向链表直接插入删除 |
NOTE
STL 的代码经过了数十年的优化和测试,比你手写的绝大多数实现更高效、更可靠。学会使用 STL 是 C++ 学习的重要里程碑。
二、vector —— 动态数组 🧩
1. 什么是 vector?
vector 是一个可以自动扩容的数组。与普通数组不同,它不需要事先指定大小,可以随时添加或删除元素。
cpp
#include <iostream>
#include <vector> // 使用 vector 需要包含这个头文件
using namespace std;
int main() {
// 创建 vector
vector<int> v; // 空的 vector
vector<int> v2(5); // 包含 5 个元素,默认都是 0
vector<int> v3(5, 10); // 包含 5 个元素,都是 10
vector<int> v4 = {1, 2, 3, 4, 5}; // 直接初始化
cout << "v3: ";
for (int i = 0; i < v3.size(); i++) {
cout << v3[i] << " "; // 像普通数组一样访问
}
cout << endl;
return 0;
}2. 常用操作
cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v;
// 添加元素
v.push_back(10); // 在末尾添加 10
v.push_back(20); // 在末尾添加 20
v.push_back(30); // 在末尾添加 30
v.push_back(40); // 在末尾添加 40
cout << "添加后:";
for (int i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}
cout << endl;
// 访问元素
cout << "第一个元素:" << v.front() << endl; // 10
cout << "最后一个元素:" << v.back() << endl; // 40
cout << "下标为2的元素:" << v[2] << endl; // 30
// 修改元素
v[1] = 99;
// 删除最后一个元素
v.pop_back();
// 获取大小
cout << "当前大小:" << v.size() << endl; // 3
// 判断是否为空
cout << "是否为空:" << v.empty() << endl; // 0 (false)
// 清空所有元素
v.clear();
cout << "清空后大小:" << v.size() << endl; // 0
return 0;
}3. vector 的常用方法一览
| 方法 | 功能 | 示例 |
|---|---|---|
push_back(x) | 在末尾添加元素 | v.push_back(10) |
pop_back() | 删除末尾元素 | v.pop_back() |
size() | 返回元素个数 | int n = v.size() |
empty() | 判断是否为空 | if (v.empty()) |
clear() | 清空所有元素 | v.clear() |
front() | 返回第一个元素 | int a = v.front() |
back() | 返回最后一个元素 | int b = v.back() |
at(i) | 安全访问(会检查越界) | v.at(3) |
insert(pos, x) | 在指定位置插入 | v.insert(v.begin()+2, 5) |
erase(pos) | 删除指定位置的元素 | v.erase(v.begin()+1) |
TIP
用 v[i] 访问时不会检查下标是否越界。如果下标超出范围,可能读到垃圾值或导致程序崩溃。如果希望安全访问,用 v.at(i)——它在越界时会抛出异常。
4. vector 的遍历方式
cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {10, 20, 30, 40, 50};
// 方式1:下标遍历(最熟悉的方式)
cout << "方式1:";
for (int i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}
cout << endl;
// 方式2:范围 for 循环(C++11 起,最推荐)
cout << "方式2:";
for (int x : v) {
cout << x << " ";
}
cout << endl;
// 方式3:迭代器遍历
cout << "方式3:";
for (auto it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
return 0;
}三、string —— 字符串 🔤
还记得 C 风格的字符串吗?——char 数组、\0 结尾、不能直接赋值、操作麻烦……
C++ 的 string 把这些烦恼全部解决了!
cpp
#include <iostream>
#include <string> // 使用 string 需要包含这个头文件
using namespace std;
int main() {
// 创建字符串
string s1 = "Hello";
string s2("World");
string s3; // 空字符串
// 直接赋值(C 风格字符串做不到!)
s1 = "C++ is awesome!";
// 拼接
string s = "Hello" + " " + "C++";
cout << s << endl; // Hello C++
// 获取长度
cout << "长度:" << s.length() << endl; // 9
cout << "长度:" << s.size() << endl; // 9(和 length 一样)
// 访问字符
cout << "第一个字符:" << s[0] << endl; // H
cout << "最后一个字符:" << s.back() << endl; // +
// 比较(直接用 == 和 !=,超方便)
if (s1 == s2) {
cout << "相等" << endl;
} else {
cout << "不相等" << endl;
}
// 输入
string name;
cout << "请输入你的名字:";
getline(cin, name); // 可以输入带空格的整行文本
cout << "你好," << name << "!" << endl;
return 0;
}string 的常用方法
| 方法 | 功能 | 示例 |
|---|---|---|
length() / size() | 返回字符串长度 | s.length() |
empty() | 判断是否为空 | if (s.empty()) |
s[i] | 访问第 i 个字符 | char c = s[0] |
+ | 拼接字符串 | s = s1 + s2 |
==, !=, <, > | 比较字符串 | if (s1 == s2) |
find(sub) | 查找子串位置 | int pos = s.find("lo") |
substr(pos, len) | 提取子串 | string sub = s.substr(1, 3) |
insert(pos, str) | 插入字符串 | s.insert(3, "xx") |
erase(pos, len) | 删除子串 | s.erase(1, 2) |
getline(cin, s) | 读取整行(含空格) | getline(cin, s) |
示例:字符串查找和提取
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "My name is Alice. I love C++.";
// 查找
size_t pos = s.find("Alice");
if (pos != string::npos) {
cout << "找到了,位置在:" << pos << endl; // 11
// 提取子串
string name = s.substr(pos, 5);
cout << "提取的名字:" << name << endl; // Alice
}
// 替换
s.replace(pos, 5, "Bob");
cout << "替换后:" << s << endl; // My name is Bob...
return 0;
}四、sort —— 排序函数 📊
之前我们手动实现了冒泡排序、选择排序、插入排序。但其实 C++ 标准库自带了一个超级好用的排序函数——sort()!
cpp
#include <iostream>
#include <algorithm> // sort 需要这个头文件
#include <vector>
using namespace std;
int main() {
// 对普通数组排序
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
sort(arr, arr + n); // 默认升序排序
cout << "数组升序:";
for (int i = 0; i < n; i++) cout << arr[i] << " ";
cout << endl;
// 对 vector 排序
vector<int> v = {5, 3, 8, 1, 9, 2};
sort(v.begin(), v.end()); // 升序
cout << "vector升序:";
for (int x : v) cout << x << " ";
cout << endl;
// 降序排序
sort(v.begin(), v.end(), greater<int>()); // 降序
cout << "vector降序:";
for (int x : v) cout << x << " ";
cout << endl;
return 0;
}输出:
数组升序:11 12 22 25 64
vector升序:1 2 3 5 8 9
vector降序:9 8 5 3 2 1TIP
sort() 内部使用的是 快速排序 + 插入排序 + 堆排序 的混合算法(IntroSort),时间复杂度平均 O(n log n),比我们自己手写的冒泡排序(O(n²))快得多!
所以实际开发中:优先用 sort(),只有在学习算法原理时才自己实现排序。
五、更多 STL 容器一览 🗂️
| 容器 | 头文件 | 特点 | 适用场景 |
|---|---|---|---|
vector | <vector> | 动态数组,支持随机访问 | 最常用的容器,替代普通数组 |
string | <string> | 字符串,支持各种操作 | 代替 C 风格字符串 |
list | <list> | 双向链表,快速插入删除 | 频繁在中间插入/删除数据 |
stack | <stack> | 栈,后进先出(LIFO) | 括号匹配、函数调用栈 |
queue | <queue> | 队列,先进先出(FIFO) | 排队系统、BFS 算法 |
map | <map> | 键值对,自动排序 | 字典、成绩查询、计数 |
set | <set> | 集合,元素不重复且有序 | 去重、快速查找是否存在 |
NOTE
这些容器在后续的 L3 和算法学习中会逐步接触到。现阶段,先把 vector、string、sort 这三个用熟练就足够了!
六、综合示例 💻
cpp
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main() {
// 学生成绩管理系统(STL 版本)
vector<string> names;
vector<int> scores;
int n;
cout << "请输入学生人数:";
cin >> n;
// 输入学生信息
for (int i = 0; i < n; i++) {
string name;
int score;
cout << "请输入第 " << i + 1 << " 个学生的姓名和成绩:";
cin >> name >> score;
names.push_back(name);
scores.push_back(score);
}
// 输出原始数据
cout << "\n=== 学生成绩 ===" << endl;
for (int i = 0; i < n; i++) {
cout << names[i] << "\t" << scores[i] << endl;
}
// 按成绩排序(使用 sort)
// 提示:这里我们对成绩排序,但需要同时保持姓名对应
// 更完整的做法是使用结构体,这里为了演示简单
sort(scores.begin(), scores.end());
cout << "\n=== 成绩排名(升序)===" << endl;
for (int i = 0; i < n; i++) {
cout << "第 " << i + 1 << " 名:" << scores[i] << endl;
}
// 计算平均分
int sum = 0;
for (int s : scores) {
sum += s;
}
double avg = (double)sum / n;
cout << "\n平均分:" << avg << endl;
return 0;
}七、小结 🎯
- STL 是 C++ 的标准工具箱,包含容器、算法和迭代器。
vector:动态数组,自动管理内存,最常用的容器。string:C++ 字符串,支持拼接、查找、截取等操作。sort():高效排序函数,O(n log n),比手写排序快。- 学会使用 STL 可以大幅提高编程效率和代码质量。
八、练习 📝
vector 基本操作:创建一个
vector<int>,输入 10 个整数,然后输出它们的和与平均值。去重:输入 n 个整数,用
vector存储,用sort排序,然后输出去重后的结果(提示:相邻元素比较)。字符串反转:输入一个字符串,用
string存储,将其反转后输出。(提示:可以用reverse(s.begin(), s.end()))统计字母出现次数:输入一行英文文本,统计每个字母(忽略大小写)出现的次数,输出出现次数最多的字母及其次数。
成绩排名(结构体版):定义一个
struct Student { string name; int score; },使用vector<Student>存储学生信息,用sort按成绩从高到低排序并输出。回文判断:输入一个字符串,判断它是否为回文(正着读和反着读一样)。例如
"abcba"是回文,"hello"不是。挑战题:合并两个有序数组:给定两个已排序的
vector<int>,将它们合并为一个有序的vector<int>,不使用sort函数(提示:双指针法)。