以下是C++基础教育第六课,聚焦STL标准模板库核心组件,掌握现代C++高效编程的瑞士军刀:


C++基础教育第六课:STL标准模板库精要

一、课程导语

"STL是C++给程序员的礼物——本节课我们将深入探索容器、算法与迭代器的黄金组合,体验工业级代码的优雅与效率。"

二、核心知识点

  1. 容器家族:顺序容器与关联容器

  2. 迭代器模式:统一访问接口

  3. 算法库:泛型编程实践

  4. 适配器模式:栈与队列实现

  5. 分配器:内存管理定制

三、实操环节

1. 顺序容器实战

(1) vector动态数组

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> nums;  // 空vector

    // 尾部插入
    nums.push_back(10);
    nums.push_back(20);
    nums.push_back(30);

    // 随机访问
    cout << "第2个元素: " << nums[1] << endl;  // 20 (无边界检查)
    cout << "安全访问: " << nums.at(1) << endl; // 20 (越界抛出异常)

    // 迭代器遍历
    for(auto it = nums.begin(); it != nums.end(); ++it) {
        cout << *it << " ";  // 10 20 30
    }

    // 容量管理
    nums.reserve(100);  // 预分配空间
    cout << "容量: " << nums.capacity() << endl;

    return 0;
}

性能特点

  • 随机访问O(1)

  • 尾部插入平均O(1)

  • 中间插入O(n)


(2) list双向链表

#include <list>
// ...(省略头文件)

list<int> dataList = {1, 2, 3};

// 任意位置插入
auto it = dataList.begin();
++it;  // 指向2
dataList.insert(it, 99);  // 列表变为1,99,2,3

// 高效删除
dataList.erase(it);  // 删除99

// 反向遍历
for(auto rit = dataList.rbegin(); rit != dataList.rend(); ++rit) {
    cout << *rit << " ";  // 3 2 1
}

适用场景

  • 频繁在任意位置插入/删除

  • 不需要随机访问


2. 关联容器进阶

(1) map键值对词典

#include <map>
#include <string>

map<string, int> wordCount;

// 插入元素
wordCount["apple"] = 3;
wordCount.insert({"banana", 5});

// 查找元素
if(wordCount.find("orange") == wordCount.end()) {
    cout << "未找到orange" << endl;
}

// 遍历map
for(const auto &pair : wordCount) {
    cout << pair.first << ": " << pair.second << endl;
}

底层实现

  • 红黑树保证有序性(按键升序排列)

  • 查找/插入/删除时间复杂度O(log n)


(2) unordered_set哈希集合

#include <unordered_set>

unordered_set<int> uniqueNumbers = {1, 2, 3, 2, 1};
// 自动去重,实际存储{1,2,3}

// 快速存在性检查
if(uniqueNumbers.count(2)) {
    cout << "2存在集合中" << endl;
}

// 自定义哈希函数示例(用于自定义类型)
struct Point {
    int x, y;
};

struct PointHash {
    size_t operator()(const Point &p) const {
        return hash<int>()(p.x) ^ hash<int>()(p.y);
    }
};

unordered_set<Point, PointHash> pointSet;

3. 算法与迭代器

(1) 常用算法示例

#include <algorithm>
#include <numeric>  // 数值算法

vector<int> data = {3, 1, 4, 1, 5, 9};

// 排序
sort(data.begin(), data.end());  // 1,1,3,4,5,9

// 查找
auto it = find(data.begin(), data.end(), 4);
if(it != data.end()) {
    cout << "找到4,位置: " << distance(data.begin(), it) << endl;
}

// 统计
int count = count_if(data.begin(), data.end(), 
    [](int x){ return x > 3; });  // 统计大于3的元素

// 累加
int sum = accumulate(data.begin(), data.end(), 0);

(2) 自定义比较函数

// 降序排序
sort(data.begin(), data.end(), greater<int>());

// 自定义结构体排序
struct Student {
    string name;
    int score;
};

vector<Student> students = {{"Alice",90}, {"Bob",85}, {"Carol",95}};

sort(students.begin(), students.end(), 
    [](const Student &a, const Student &b) {
        return a.score > b.score;  // 按分数降序
    });

4. 适配器容器

(1) stack后进先出

#include <stack>

stack<int> calcStack;
calcStack.push(10);
calcStack.push(20);
calcStack.push(30);

cout << "栈顶: " << calcStack.top() << endl;  // 30
calcStack.pop();  // 移除30
cout << "新栈顶: " << calcStack.top() << endl; // 20

(2) queue先进先出

#include <queue>

queue<string> taskQueue;
taskQueue.push("任务A");
taskQueue.push("任务B");

cout << "下一个任务: " << taskQueue.front() << endl;  // 任务A
taskQueue.pop();  // 移除任务A
cout << "新任务: " << taskQueue.front() << endl;     // 任务B

四、底层原理剖析

1. 迭代器失效规则

操作类型 vector/string list/deque map/set
插入元素 可能失效 不失效 不失效
删除元素 后续迭代器失效 仅被删元素失效 仅被删元素失效
扩容(reserve) 全部失效 不适用 不适用

安全编程建议

  • 使用erase返回值更新迭代器:

    for(auto it = vec.begin(); it != vec.end(); ) {
        if(*it % 2 == 0) {
            it = vec.erase(it);  // erase返回下一个有效迭代器
        } else {
            ++it;
        }
    }
    

2. 分配器机制

#include <memory>

// 自定义分配器示例
template<typename T>
class MyAllocator {
public:
    T* allocate(size_t n) {
        cout << "分配 "<< n << " 个T对象" << endl;
        return static_cast<T*>(::operator new(n * sizeof(T)));
    }

    void deallocate(T* p, size_t n) {
        cout << "释放 "<< n << " 个T对象" << endl;
        ::operator delete(p);
    }
};

vector<int, MyAllocator<int>> customVec;  // 使用自定义分配器

五、课后实战任务

基础挑战

  1. 实现学生成绩管理系统:

    • 使用map<string, vector<int>>存储学生姓名与成绩列表

    • 提供添加成绩、计算平均分功能

进阶挑战

  1. 设计文本词频统计工具:

    • 使用unordered_map<string, int>统计单词出现次数

    • 按词频降序输出Top 10高频词

  2. 实现迷宫求解算法:

    • queue<pair<int,int>>实现广度优先搜索(BFS)

    • 记录路径并可视化输出


六、常见问题解答

  1. Q:vector和list如何选择?

    A:

    • 需要随机访问 → vector

    • 频繁在中间插入/删除 → list

    • 元素数量变化大 → vector(预留空间)或deque

  2. Q:map和unordered_map性能对比?

    A:

    • 查找/插入平均时间复杂度:

      • map: O(log n)

      • unordered_map: O(1)(最坏情况O(n))

    • 内存占用:unordered_map通常更高

  3. Q:STL容器线程安全吗?

    A:

    • 不同容器实例可安全并发访问

    • 同一容器多线程操作需外部同步(如mutex)

    • C++17引入并行算法(std::execution::par


"STL不是束缚你的枷锁,而是让你站在巨人肩膀上的阶梯——掌握它,你将获得工业级开发的生产力!"

(本课代码已在C++17标准下验证,推荐使用Clang-Tidy检查STL使用规范)

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐