一、什么是 STL

STL 全称 Standard Template Library 标准模板库,是 C++ 标准库核心组成部分。 它不只是一堆可复用工具函数,更是一套封装数据结构 + 通用算法的完整软件框架。 C++ 标准库整体分为三块:C 库、IO 库、STL,STL 是其中模板化、容器化的核心模块。

二、STL 四大历史版本

STL 起源惠普实验室,衍生出 4 个主流分支,不同平台底层实现不同:

  1. HP 原始版本(始祖) Alexander Stepanoff、Meng Lee 在惠普实验室开发,开源协议宽松:允许商用、修改、分发,唯一要求衍生代码同样开源。所有 STL 实现的底层源头。

  2. P.J. 版本(Windows) 继承 HP 版本,被 VS (Visual C++) 采用,闭源商用。缺点:代码可读性差、命名风格怪异,无法查看修改底层源码。

  3. RW 版本(旧版 Windows/macOS) Rogue Wave 公司出品,闭源商用,用于老版 C++ Builder,可读性一般。

  4. SGI 版本(Linux/GCC,学习首选) Silicon Graphics 公司开发,继承 HP,GCC 编译器默认实现。 优势:完全开源、可自由修改分发、命名规范、源码注释清晰。学习 STL 底层原理、阅读源码首选 SGI 版本

三、STL 六大核心组件(整体架构)

一张图看懂 STL 完整分层:

  1. 容器 Container(数据结构) 存储数据的结构,分为三类:

    1. 顺序容器:stringvectorlistdeque

    2. 关联容器:mapsetmultimapmultiset

    3. 容器适配器(改造容器):stackqueuepriority_queue

  2. 算法 Algorithm 通用操作函数,与容器解耦:sortreversefindswapmerge 等。 核心设计:一套算法,适配所有容器,不靠容器内置方法实现。

  3. 迭代器 Iterator 容器和算法的桥梁,模拟指针行为:iteratorconst_iteratorreverse_iteratorconst_reverse_iterator。 算法只操作迭代器,不感知底层容器结构,实现低耦合。

  4. 仿函数 Functor 重载()的类,用作算法比较规则:greaterless,替代函数指针,功能更强。

  5. 空间配置器 Allocator 容器底层内存池管理,封装内存分配、释放逻辑,优化内存碎片。

  6. 配接器 Adapter 分容器适配器、迭代器适配器、函数适配器,对原有组件二次封装(如 stack 基于 deque 改造)。

STL 学习三层境界

  1. 第一层:熟用 STL —— 会调用容器、算法解决业务 / 算法题

  2. 第二层:吃透底层 —— 理解模板泛型原理、容器底层实现、迭代器解耦逻辑

  3. 第三层:扩展 STL —— 自定义容器、仿函数、分配器,造轮子

四、string 字符串详解

1. string 底层体系:宽字符与编码

std::string 本质是模板别名:

typedef basic_string<char> string;

配套多字节宽字符串,适配 Unicode 编码:

  • wstringbasic_string<wchar_t> 老 Windows 宽字符

  • u16stringbasic_string<char16_t> UTF-16 编码

  • u32stringbasic_string<char32_t> UTF-32 编码

编码概念区分:

  • ASCII:单字节英文老字符集

  • Unicode:字符 - 符号映射表(统一给全球文字分配编号)

  • UTF-8/UTF-16/UTF-32:Unicode 的存储编码方案(变长 / 定长存储)

UTF-8 变长编码规则(连蒙带猜快速识别)

UTF-8 是 1~4 字节变长编码,通过首字节高位判断字符占用字节:

  1. 首字节以0开头:单字节 ASCII 字符

  2. 首字节110开头:双字节字符

  3. 首字节1110开头:三字节字符

  4. 首字节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());
迭代器 + 算法的两大核心意义
  1. 统一遍历接口:vector、list、string 结构完全不同,但都能用begin/end迭代器遍历,写法统一。

  2. 容器与算法解耦:算法不依赖容器底层结构,只操作迭代器;新增容器只要实现迭代器,所有 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;
    }
};

六、学习总结

  1. STL 核心价值:模板泛型实现数据结构 + 算法复用,大幅减少重复造轮子;

  2. 迭代器是 STL 灵魂,实现算法与容器解耦,一套算法通用所有容器;

  3. string 基于basic_string模板封装,区分多套宽字符适配不同编码;

  4. 刷题优先掌握迭代器遍历、双指针、计数数组三大 string 常用技巧。

更多推荐