C++ STL 完整入门笔记[0]:从概念到string实战刷题
一、什么是 STL
STL 全称 Standard Template Library 标准模板库,是 C++ 标准库核心组成部分。 它不只是一堆可复用工具函数,更是一套封装数据结构 + 通用算法的完整软件框架。 C++ 标准库整体分为三块:C 库、IO 库、STL,STL 是其中模板化、容器化的核心模块。
二、STL 四大历史版本
STL 起源惠普实验室,衍生出 4 个主流分支,不同平台底层实现不同:
-
HP 原始版本(始祖) Alexander Stepanoff、Meng Lee 在惠普实验室开发,开源协议宽松:允许商用、修改、分发,唯一要求衍生代码同样开源。所有 STL 实现的底层源头。
-
P.J. 版本(Windows) 继承 HP 版本,被 VS (Visual C++) 采用,闭源商用。缺点:代码可读性差、命名风格怪异,无法查看修改底层源码。
-
RW 版本(旧版 Windows/macOS) Rogue Wave 公司出品,闭源商用,用于老版 C++ Builder,可读性一般。
-
SGI 版本(Linux/GCC,学习首选) Silicon Graphics 公司开发,继承 HP,GCC 编译器默认实现。 优势:完全开源、可自由修改分发、命名规范、源码注释清晰。学习 STL 底层原理、阅读源码首选 SGI 版本。
三、STL 六大核心组件(整体架构)
一张图看懂 STL 完整分层:
-
容器 Container(数据结构) 存储数据的结构,分为三类:
-
顺序容器:
string、vector、list、deque -
关联容器:
map、set、multimap、multiset -
容器适配器(改造容器):
stack、queue、priority_queue
-
-
算法 Algorithm 通用操作函数,与容器解耦:
sort、reverse、find、swap、merge等。 核心设计:一套算法,适配所有容器,不靠容器内置方法实现。 -
迭代器 Iterator 容器和算法的桥梁,模拟指针行为:
iterator、const_iterator、reverse_iterator、const_reverse_iterator。 算法只操作迭代器,不感知底层容器结构,实现低耦合。 -
仿函数 Functor 重载
()的类,用作算法比较规则:greater、less,替代函数指针,功能更强。 -
空间配置器 Allocator 容器底层内存池管理,封装内存分配、释放逻辑,优化内存碎片。
-
配接器 Adapter 分容器适配器、迭代器适配器、函数适配器,对原有组件二次封装(如 stack 基于 deque 改造)。
STL 学习三层境界
-
第一层:熟用 STL —— 会调用容器、算法解决业务 / 算法题
-
第二层:吃透底层 —— 理解模板泛型原理、容器底层实现、迭代器解耦逻辑
-
第三层:扩展 STL —— 自定义容器、仿函数、分配器,造轮子
四、string 字符串详解
1. string 底层体系:宽字符与编码
std::string 本质是模板别名:
typedef basic_string<char> string;
配套多字节宽字符串,适配 Unicode 编码:
-
wstring:basic_string<wchar_t>老 Windows 宽字符 -
u16string:basic_string<char16_t>UTF-16 编码 -
u32string:basic_string<char32_t>UTF-32 编码
编码概念区分:
-
ASCII:单字节英文老字符集
-
Unicode:字符 - 符号映射表(统一给全球文字分配编号)
-
UTF-8/UTF-16/UTF-32:Unicode 的存储编码方案(变长 / 定长存储)
UTF-8 变长编码规则(连蒙带猜快速识别)
UTF-8 是 1~4 字节变长编码,通过首字节高位判断字符占用字节:
-
首字节以
0开头:单字节 ASCII 字符 -
首字节
110开头:双字节字符 -
首字节
1110开头:三字节字符 -
首字节
11110开头:四字节字符 后续延续字节统一以10开头。
2. string 核心接口
(1)npos 静态常量
static const size_t npos = -1;
字符串查找失败时的返回标记,无匹配字符就返回npos。
(2)下标访问 operator []
string s1("hello world");
const string s2("hello world");
s1[0]++; // 可读写,非const字符串
s2[0]++; // 编译报错,const字符串仅可读
底层存储:_str字符数组指针、_size有效长度、_capacity总容量。
(3)迭代器遍历
迭代器是模仿指针的对象,begin()获取首元素迭代器,end()获取末尾后一位迭代器:
string::iterator it1 = s1.begin();
while (it1 != s1.end())
{
(*it1)--;
++it1;
}
cout << s1 << endl;
3. 通用算法 reverse:解耦设计精髓
std::reverse 是函数模板,接收一对双向迭代器,反转区间[first, last)内元素:
// string反转 reverse(s1.begin(), s1.end()); // vector反转 reverse(v.begin(), v.end()); // list反转 reverse(lt.begin(), lt.end());
迭代器 + 算法的两大核心意义
-
统一遍历接口:vector、list、string 结构完全不同,但都能用
begin/end迭代器遍历,写法统一。 -
容器与算法解耦:算法不依赖容器底层结构,只操作迭代器;新增容器只要实现迭代器,所有 STL 算法直接复用,不用重写反转、排序逻辑。
五、LeetCode string 实战刷题
例题 1:917. 仅仅反转字母
题目规则:仅反转英文字母,非字母字符位置保持不变。 双指针思路:左指针从头、右指针从尾,跳过符号数字,交换两边字母。
class Solution {
public:
bool isLetter(char ch)
{
if(ch >= 'a' && ch <= 'z') return true;
if(ch >= 'A' && ch <= 'Z') return true;
return false;
}
string reverseOnlyLetters(string s) {
size_t begin = 0, end = s.size()-1;
while(begin < end)
{
while(begin < end && !isLetter(s[begin]))
++begin;
while(begin < end && !isLetter(s[end]))
--end;
swap(s[begin], s[end]);
++begin;
--end;
}
return s;
}
};
例题 2:387. 字符串中的第一个唯一字符
思路:数组统计 26 个小写字母出现次数,第二次遍历找到第一个计数为 1 的下标。
class Solution {
public:
int firstUniqChar(string s) {
int count[26] = {0};
// 统计频次
for(auto ch : s)
{
count[ch-'a']++;
}
// 遍历找第一个仅出现一次的字符
for(size_t i = 0; i < s.size(); ++i)
{
if(count[s[i]-'a'] == 1)
return i;
}
return -1;
}
};
六、学习总结
-
STL 核心价值:模板泛型实现数据结构 + 算法复用,大幅减少重复造轮子;
-
迭代器是 STL 灵魂,实现算法与容器解耦,一套算法通用所有容器;
-
string 基于
basic_string模板封装,区分多套宽字符适配不同编码; -
刷题优先掌握迭代器遍历、双指针、计数数组三大 string 常用技巧。
更多推荐
所有评论(0)