STL(标准模板库)是 C++ 的核心工具集,其中容器作为数据存储的核心组件,涵盖了动态数组、链表、栈、队列等多种数据结构。掌握容器的常用方法是 STL 入门的关键,本文将结合实战代码,详细拆解 string、vector、list、stack、queue 等核心容器的常用接口,帮你快速上手 STL 开发。

一、STL 容器入门基础

1. 容器本质与核心价值

STL 容器是封装了数据结构的模板类,无需手动管理内存,提供了统一的操作接口。其核心价值在于:

  • 避免重复开发底层数据结构(如动态数组、链表)。
  • 接口标准化,降低学习成本(如size()empty()在各容器中通用)。
  • 适配算法库,可直接搭配sort()find()等算法使用。

2. 容器分类与选择建议

容器类型代表容器核心特点适用场景
序列式容器string、vector元素有序存储,支持下标访问频繁查询、少量插入删除
链表式容器list元素双向链接,插入删除高效大量插入删除、无需随机访问
容器适配器stack、queue封装基础容器,限制访问方式栈(LIFO)、队列(FIFO)场景
优先队列priority_queue自动按优先级排序TopK 问题、任务调度

二、核心容器常用方法 + 实战代码

1. string 类:字符串高效管理

string 是专门处理字符串的容器,封装了 C 语言字符串的缺陷,提供了丰富的字符串操作接口。

常用方法速查表
方法分类常用方法功能说明
构造与初始化string()、string(const char* s)空构造、用 C 字符串构造
string(size_t n, char c)构造含 n 个字符 c 的字符串
容量操作size()/length()返回有效字符长度(功能一致)
capacity()返回总存储空间大小
empty()判断是否为空串(空返回 true)
reserve(size_t n)预留 n 个字符空间(不初始化,提升效率)
resize(size_t n, char c)调整有效字符数为 n,多余部分用 c 填充
访问与遍历operator[] (pos)直接访问 pos 位置字符(越界风险)
begin()/end()正向迭代器,用于遍历
范围 for 循环C++11 特性,简化遍历逻辑
修改操作operator+= (str/char)追加字符串或字符(最常用)
push_back(char c)尾插单个字符
find(char c, pos)从 pos 开始向后找 c,返回索引(未找到返回 npos)
substr(pos, n)从 pos 开始截取 n 个字符,返回子串
clear()清空有效字符(不释放底层空间)
输入输出operator>>/operator<<标准输入输出
getline(cin, s)读取一行字符串(包括空格)
实战代码示例
#include <iostream>
#include <string>
using namespace std;

int main() {
    // 1. 构造与初始化
    string s1;                  // 空构造
    string s2("hello STL");     // C字符串构造
    string s3(5, 'a');          // 5个'a':"aaaaa"
    string s4(s2);              // 拷贝构造

    // 2. 容量操作
    cout << "s2长度:" << s2.size() << endl;       // 输出 9
    cout << "s2容量:" << s2.capacity() << endl;   // 输出 9(VS下默认不预留额外空间)
    s2.reserve(20);                                // 预留20个字符空间
    cout << "预留后容量:" << s2.capacity() << endl;// 输出 20

    // 3. 访问与遍历
    cout << "s2[0]:" << s2[0] << endl;           // 输出 'h'
    // 迭代器遍历
    for (auto it = s2.begin(); it != s2.end(); ++it) {
        cout << *it << " ";                        // 输出 h e l l o   S T L
    }
    cout << endl;
    // 范围for遍历(C++11)
    for (auto ch : s2) {
        cout << ch;                                // 输出 hello STL
    }
    cout << endl;

    // 4. 修改操作
    s2 += "!!!";                                   // 追加字符串:"hello STL!!!"
    s2.push_back('?');                             // 尾插字符:"hello STL!!!?"
    cout << "修改后:" << s2 << endl;              // 输出 hello STL!!!?

    size_t pos = s2.find('S');                     // 查找'S'的位置
    string sub = s2.substr(pos, 3);                // 截取从'S'开始的3个字符
    cout << "子串:" << sub << endl;               // 输出 STL

    // 5. 输入输出
    string s5;
    getline(cin, s5);                              // 读取一行输入(如"hello world")
    cout << "输入内容:" << s5 << endl;             // 输出 hello world

    return 0;
}

2. vector:动态数组(最常用容器)

vector 是动态增长的数组,支持随机访问,底层为连续空间,是实际开发中使用频率最高的容器。

常用方法速查表
方法分类常用方法功能说明
构造与初始化vector()空构造
vector(size_t n, T val)构造含 n 个 val 的 vector
vector(iterator first, iterator last)用迭代器区间构造
容量操作size()返回有效元素个数
capacity()返回总容量(VS 下 1.5 倍扩容,G++ 下 2 倍扩容)
empty()判断是否为空
reserve(size_t n)预留 n 个元素空间(避免频繁扩容)
resize(size_t n, T val)调整元素个数为 n,多余部分用 val 填充
访问与遍历operator[] (pos)下标访问 pos 位置元素(高效)
begin()/end()正向迭代器
rbegin()/rend()反向迭代器(从尾到头遍历)
增删操作push_back(T val)尾插元素(常用)
pop_back()尾删元素(常用)
insert(iterator pos, T val)在 pos 位置插入 val(效率低,需搬移元素)
erase(iterator pos)删除 pos 位置元素(返回下一个有效迭代器)
swap(vector& other)交换两个 vector 的内容
其他操作clear()清空所有元素(不释放空间)
实战代码示例
#include <iostream>
#include <vector>
#include <algorithm>  // 包含find算法
using namespace std;

int main() {
    // 1. 构造与初始化
    vector<int> v1;                  // 空构造
    vector<int> v2(5, 10);           // 5个10:[10,10,10,10,10]
    int arr[] = {1,2,3,4,5};
    vector<int> v3(arr, arr+5);      // 用数组区间构造:[1,2,3,4,5]

    // 2. 容量操作
    cout << "v3大小:" << v3.size() << endl;         // 输出 5
    cout << "v3容量:" << v3.capacity() << endl;     // 输出 5(G++下初始容量=大小)
    v3.reserve(10);                                  // 预留10个空间
    cout << "预留后容量:" << v3.capacity() << endl; // 输出 10

    // 3. 访问与遍历
    cout << "v3[2]:" << v3[2] << endl;             // 输出 3(下标访问)
    // 反向迭代器遍历
    for (auto it = v3.rbegin(); it != v3.rend(); ++it) {
        cout << *it << " ";                          // 输出 5 4 3 2 1
    }
    cout << endl;

    // 4. 增删操作
    v3.push_back(6);                                 // 尾插:[1,2,3,4,5,6]
    v3.pop_back();                                   // 尾删:[1,2,3,4,5]
    // 插入(在第2个元素后插入3)
    auto pos = v3.begin() + 2;
    v3.insert(pos, 3);                               // 结果:[1,2,3,3,4,5]
    // 删除(删除第一个3)
    pos = find(v3.begin(), v3.end(), 3);             // 查找3的位置
    v3.erase(pos);                                   // 结果:[1,2,3,4,5]

    // 5. 遍历输出最终结果
    for (auto e : v3) {
        cout << e << " ";                            // 输出 1 2 3 4 5
    }
    cout << endl;

    return 0;
}
关键注意点
  • 迭代器失效:insert()erase()reserve()等操作可能导致迭代器失效,需重新赋值迭代器(如pos = v3.erase(pos))。
  • 扩容机制:VS 下按 1.5 倍扩容,G++ 下按 2 倍扩容,扩容时会拷贝旧元素到新空间,建议用reserve()提前预留空间。

3. list 类:双向循环链表

list 底层是带头结点的双向循环链表,插入删除操作效率极高(无需搬移元素),但不支持随机访问。

常用方法速查表
方法分类常用方法功能说明
构造与初始化list()、list(size_t n, T val)空构造、构造含 n 个 val 的链表
容量操作size()返回有效节点个数
empty()判断是否为空
访问操作front()返回第一个元素的引用
back()返回最后一个元素的引用
增删操作push_front(T val)头插元素(高效)
push_back(T val)尾插元素(高效)
pop_front()头删元素(高效)
pop_back()尾删元素(高效)
insert(iterator pos, T val)在 pos 位置插入 val(O (1) 效率)
erase(iterator pos)删除 pos 位置元素(返回下一个迭代器)
其他操作clear()清空所有元素
swap(list& other)交换两个链表内容
实战代码示例
#include <iostream>
#include <list>
using namespace std;

int main() {
    // 1. 构造与初始化
    list<int> l1;                      // 空构造
    list<int> l2(4, 20);               // 4个20:[20,20,20,20]
    int arr[] = {10,20,30,40};
    list<int> l3(arr, arr+4);          // 用数组构造:[10,20,30,40]

    // 2. 访问操作
    cout << "首元素:" << l3.front() << endl;  // 输出 10
    cout << "尾元素:" << l3.back() << endl;   // 输出 40

    // 3. 增删操作(高效)
    l3.push_front(5);                     // 头插:[5,10,20,30,40]
    l3.push_back(45);                     // 尾插:[5,10,20,30,40,45]
    l3.pop_front();                       // 头删:[10,20,30,40,45]
    l3.pop_back();                        // 尾删:[10,20,30,40]

    // 插入和删除中间元素
    auto pos = l3.begin();
    ++pos;                                // 指向第二个元素20
    l3.insert(pos, 15);                   // 插入15:[10,15,20,30,40]
    pos = l3.begin() + 3;                 // 指向30(注意:list不支持随机访问,需迭代器移动)
    l3.erase(pos);                        // 删除30:[10,15,20,40]

    // 4. 遍历输出
    for (auto e : l3) {
        cout << e << " ";                 // 输出 10 15 20 40
    }
    cout << endl;

    return 0;
}
关键注意点
  • 不支持随机访问:不能用l3[2]访问元素,需通过迭代器移动(如++pos)。
  • 迭代器失效:仅删除元素时,被删除节点的迭代器失效,其他迭代器不受影响(与 vector 不同)。

4. stack 类:栈(容器适配器)

stack 是基于其他容器(默认 deque)封装的适配器,遵循 “后进先出(LIFO)” 原则,仅支持栈顶操作。

常用方法速查表
方法分类常用方法功能说明
构造与初始化stack()空构造
容量操作empty()判断栈是否为空(空返回 true)
size()返回栈中元素个数
核心操作push(T val)栈顶压入元素
pop()栈顶弹出元素(无返回值)
top()返回栈顶元素的引用(不弹出)
实战代码示例:最小栈实现
#include <iostream>
#include <stack>
using namespace std;

// 设计一个支持getMin()的最小栈
class MinStack {
public:
    void push(int x) {
        _elem.push(x);  // 元素入栈
        // 最小栈为空或x小于等于栈顶,入栈
        if (_min.empty() || x <= _min.top()) {
            _min.push(x);
        }
    }

    void pop() {
        // 若弹出的是最小值,最小栈也弹出
        if (_elem.top() == _min.top()) {
            _min.pop();
        }
        _elem.pop();
    }

    int top() {
        return _elem.top();  // 返回栈顶元素
    }

    int getMin() {
        return _min.top();   // 返回最小值
    }

private:
    stack<int> _elem;  // 存储所有元素
    stack<int> _min;   // 存储最小值(辅助栈)
};

int main() {
    MinStack ms;
    ms.push(3);
    ms.push(2);
    ms.push(5);
    ms.push(1);

    cout << "栈顶元素:" << ms.top() << endl;    // 输出 1
    cout << "当前最小值:" << ms.getMin() << endl;// 输出 1

    ms.pop();  // 弹出1(最小值)
    cout << "弹出后最小值:" << ms.getMin() << endl;// 输出 2

    return 0;
}

5. queue 类:队列(容器适配器)

queue 基于 deque 或 list 封装,遵循 “先进先出(FIFO)” 原则,支持队尾入队、队头出队。

常用方法速查表
方法分类常用方法功能说明
构造与初始化queue()空构造
容量操作empty()判断队列是否为空
size()返回队列元素个数
核心操作push(T val)队尾入队
pop()队头出队(无返回值)
front()返回队头元素引用
back()返回队尾元素引用
实战代码示例:队列模拟
#include <iostream>
#include <queue>
using namespace std;

int main() {
    queue<int> q;

    // 入队操作
    q.push(10);
    q.push(20);
    q.push(30);

    cout << "队列大小:" << q.size() << endl;    // 输出 3
    cout << "队头元素:" << q.front() << endl;   // 输出 10
    cout << "队尾元素:" << q.back() << endl;    // 输出 30

    // 出队操作
    q.pop();  // 弹出10
    cout << "出队后队头:" << q.front() << endl; // 输出 20

    // 遍历队列(需出队操作)
    while (!q.empty()) {
        cout << q.front() << " ";                // 输出 20 30
        q.pop();
    }
    cout << endl;

    return 0;
}

6. priority_queue:优先队列

priority_queue 默认基于 vector 封装,底层是大根堆,元素自动按优先级排序(默认降序)。

常用方法速查表
方法分类常用方法功能说明
构造与初始化priority_queue()空构造(大根堆)
priority_queue(first, last)用迭代器区间构造
priority_queue(vector<T>, greater<T>)构造小根堆
容量操作empty()、size()判断为空、返回元素个数(同 stack)
核心操作push(T val)入队(自动调整堆结构)
pop()出队(删除堆顶元素)
top()返回堆顶元素(最大值 / 最小值)
实战代码示例:TopK 问题
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

// 找出数组中第K大的元素
int findKthLargest(vector<int>& nums, int k) {
    // 构造小根堆(容量为k)
    priority_queue<int, vector<int>, greater<int>> pq;

    for (int num : nums) {
        pq.push(num);
        // 堆大小超过k,弹出最小值(保持堆顶为第k大)
        if (pq.size() > k) {
            pq.pop();
        }
    }

    return pq.top();  // 堆顶即为第k大元素
}

int main() {
    vector<int> nums = {3,2,1,5,6,4};
    int k = 2;
    cout << "第" << k << "大的元素:" << findKthLargest(nums, k) << endl; // 输出 5

    return 0;
}

三、容器使用避坑指南

  1. 迭代器失效处理
    • vector:insert()erase()reserve()后,迭代器需重新赋值(如it = v.erase(it))。
    • list:仅删除节点的迭代器失效,其他迭代器可正常使用。
  2. 内存效率优化
    • string/vector:提前用reserve()预留空间,减少扩容次数。
    • list:避免频繁创建小节点(易造成内存碎片)。
  3. 接口使用误区
    • string 的c_str()返回的指针有效期与 string 对象一致,不可长期保存。
    • stack/queue 无迭代器,不可遍历(需通过出队 / 出栈操作间接遍历)。

更多推荐