当前位置: 首页 > news >正文

【学习笔记03】C++STL标准模板库核心技术详解

📝 说明:本文为学习笔记,AI辅助整理。目的是系统梳理C++STL标准模板库核心知识,方便复习和查阅。
课时03:掌握C++标准库的强大武器,提升编程效率和代码质量
日期:2025年10月6日
难度:⭐⭐⭐⭐☆ | 时长:2小时 | 类型:实战必修

🎯 学习目标

通过本课时的学习,你将掌握:

  • STL三大组件:容器、迭代器、算法的核心原理
  • 常用容器的特性、时间复杂度和使用场景
  • 迭代器的分类和使用技巧
  • 常用算法的实际应用和性能考量
  • 面试中STL的高频考点和最佳实践

📚 STL核心架构

🎯 STL三大组件关系图

STL标准模板库
容器 Containers
迭代器 Iterators
算法 Algorithms
函数对象 Functors
适配器 Adapters
分配器 Allocators
序列容器
关联容器
无序容器
输入迭代器
输出迭代器
前向迭代器
双向迭代器
随机访问迭代器
修改算法
非修改算法
排序算法

🔍 1. 容器详解

📦 序列容器(Sequence Containers)

vector - 动态数组
#include <vector>
#include <iostream>
using namespace std;void demonstrateVector() {// 1. 初始化方式vector<int> v1;                    // 空vectorvector<int> v2(5);                 // 5个元素,默认值0vector<int> v3(5, 10);             // 5个元素,值为10vector<int> v4{1, 2, 3, 4, 5};     // 初始化列表vector<int> v5(v4.begin(), v4.end()); // 迭代器范围初始化// 2. 容量管理cout << "大小:" << v4.size() << endl;        // 当前元素数量cout << "容量:" << v4.capacity() << endl;    // 已分配空间cout << "最大容量:" << v4.max_size() << endl; // 理论最大容量v4.reserve(100);  // 预分配空间,避免频繁重新分配v4.shrink_to_fit(); // 释放多余空间// 3. 元素访问cout << "第一个元素:" << v4[0] << endl;      // 操作符[]cout << "第一个元素:" << v4.at(0) << endl;   // at()有边界检查cout << "第一个元素:" << v4.front() << endl; // 第一个元素cout << "最后元素:" << v4.back() << endl;    // 最后一个元素// 4. 修改操作v4.push_back(6);      // 尾部添加 O(1)摊销v4.pop_back();        // 尾部删除 O(1)v4.insert(v4.begin() + 2, 99);  // 指定位置插入 O(n)v4.erase(v4.begin() + 2);       // 删除指定位置 O(n)// 5. 遍历方式// 传统for循环for (size_t i = 0; i < v4.size(); ++i) {cout << v4[i] << " ";}// 迭代器for (auto it = v4.begin(); it != v4.end(); ++it) {cout << *it << " ";}// 范围for(推荐)for (const auto& element : v4) {cout << element << " ";}
}
deque - 双端队列
#include <deque>void demonstrateDeque() {deque<int> dq{1, 2, 3, 4, 5};// 双端操作 - deque的优势dq.push_front(0);    // 头部插入 O(1)dq.push_back(6);     // 尾部插入 O(1)dq.pop_front();      // 头部删除 O(1)dq.pop_back();       // 尾部删除 O(1)// 随机访问(类似vector)cout << "中间元素:" << dq[dq.size()/2] << endl;// 使用场景:需要频繁头尾操作的场景// 例如:滑动窗口、广度优先搜索等
}
list - 双向链表
#include <list>void demonstrateList() {list<int> lst{3, 1, 4, 1, 5};// 任意位置高效插入删除auto it = find(lst.begin(), lst.end(), 4);lst.insert(it, 99);  // 在4之前插入99 O(1)lst.erase(it);       // 删除4 O(1)// 链表特有操作lst.sort();          // 原地排序lst.unique();        // 去除连续重复元素lst.reverse();       // 反转// 合并两个有序链表list<int> lst2{2, 6, 8};lst2.sort();lst.merge(lst2);     // 合并后lst2为空// 注意:list不支持随机访问,没有[]和at()// cout << lst[0];   // 错误!
}

🗺️ 关联容器(Associative Containers)

map - 有序键值对
#include <map>void demonstrateMap() {// 1. 初始化map<string, int> scores;map<string, int> scores2{{"Alice", 95}, {"Bob", 87}, {"Charlie", 92}};// 2. 插入操作scores["Alice"] = 95;                    // 操作符[]scores.insert({"Bob", 87});              // insert方法scores.insert(make_pair("Charlie", 92)); // make_pairscores.emplace("David", 89);             // 原地构造(效率更高)// 3. 查找操作auto it = scores.find("Alice");if (it != scores.end()) {cout << "Alice的分数:" << it->second << endl;}// 检查键是否存在if (scores.count("Eve") > 0) {cout << "Eve存在" << endl;}// C++20: contains方法// if (scores.contains("Eve")) { ... }// 4. 有序遍历(map自动按键排序)for (const auto& [name, score] : scores) {  // 结构化绑定(C++17)cout << name << ": " << score << endl;}// 5. 范围操作auto lower = scores.lower_bound("Bob");   // 第一个 >= "Bob" 的元素auto upper = scores.upper_bound("Charlie"); // 第一个 > "Charlie" 的元素for (auto it = lower; it != upper; ++it) {cout << it->first << ": " << it->second << endl;}
}
set - 有序集合
#include <set>void demonstrateSet() {set<int> numbers{3, 1, 4, 1, 5, 9, 2, 6};  // 自动去重和排序// 插入和删除numbers.insert(7);numbers.erase(1);// 查找if (numbers.find(5) != numbers.end()) {cout << "找到5" << endl;}// 集合操作set<int> set1{1, 2, 3, 4};set<int> set2{3, 4, 5, 6};set<int> result;// 交集set_intersection(set1.begin(), set1.end(),set2.begin(), set2.end(),inserter(result, result.begin()));// 并集  set_union(set1.begin(), set1.end(),set2.begin(), set2.end(),inserter(result, result.begin()));
}

🔀 无序容器(Unordered Containers)

unordered_map - 哈希表
#include <unordered_map>void demonstrateUnorderedMap() {unordered_map<string, int> wordCount;// 统计单词频率的经典应用vector<string> words{"apple", "banana", "apple", "cherry", "banana", "apple"};for (const string& word : words) {wordCount[word]++;  // 自动初始化为0再递增}// 查看哈希表信息cout << "桶数量:" << wordCount.bucket_count() << endl;cout << "负载因子:" << wordCount.load_factor() << endl;cout << "最大负载因子:" << wordCount.max_load_factor() << endl;// 自定义哈希函数(用于自定义类型)struct Person {string name;int age;bool operator==(const Person& other) const {return name == other.name && age == other.age;}};struct PersonHash {size_t operator()(const Person& p) const {return hash<string>()(p.name) ^ (hash<int>()(p.age) << 1);}};unordered_map<Person, string, PersonHash> personMap;personMap[{"Alice", 25}] = "Engineer";
}

🔄 2. 迭代器详解

🎯 迭代器类型和特性

#include <iterator>void demonstrateIterators() {vector<int> vec{1, 2, 3, 4, 5};list<int> lst{1, 2, 3, 4, 5};// 1. 随机访问迭代器(vector, deque)auto vec_it = vec.begin();vec_it += 3;           // 支持算术运算vec_it = vec_it - 1;   // 支持减法int diff = vec.end() - vec.begin();  // 支持距离计算// 2. 双向迭代器(list, map, set)auto lst_it = lst.begin();++lst_it;              // 支持前进--lst_it;              // 支持后退// lst_it += 2;        // 不支持算术运算// 3. 迭代器适配器// 反向迭代器for (auto rit = vec.rbegin(); rit != vec.rend(); ++rit) {cout << *rit << " ";  // 逆序输出}// 插入迭代器vector<int> dest;copy(vec.begin(), vec.end(), back_inserter(dest));  // 尾部插入list<int> dest2;copy(vec.begin(), vec.end(), front_inserter(dest2)); // 头部插入// 4. 迭代器失效问题vector<int> v{1, 2, 3, 4, 5};auto it = v.begin() + 2;  // 指向元素3v.push_back(6);           // 可能导致重新分配,it失效// cout << *it;           // 危险!可能崩溃// 安全做法:记录索引而非迭代器size_t index = 2;v.push_back(6);cout << v[index] << endl;  // 安全
}

⚙️ 3. 算法详解

🔍 查找算法

#include <algorithm>void demonstrateSearchAlgorithms() {vector<int> vec{3, 1, 4, 1, 5, 9, 2, 6, 5, 3};// 1. 线性查找auto it = find(vec.begin(), vec.end(), 5);if (it != vec.end()) {cout << "找到5,位置:" << distance(vec.begin(), it) << endl;}// 查找满足条件的元素auto it2 = find_if(vec.begin(), vec.end(), [](int x) { return x > 5; });if (it2 != vec.end()) {cout << "第一个大于5的元素:" << *it2 << endl;}// 2. 二分查找(需要先排序)vector<int> sorted_vec = vec;sort(sorted_vec.begin(), sorted_vec.end());bool found = binary_search(sorted_vec.begin(), sorted_vec.end(), 5);cout << "二分查找5:" << (found ? "找到" : "未找到") << endl;// 查找插入位置auto pos = lower_bound(sorted_vec.begin(), sorted_vec.end(), 5);cout << "5应该插入的位置:" << distance(sorted_vec.begin(), pos) << endl;// 3. 计数int count = count(vec.begin(), vec.end(), 1);cout << "1出现的次数:" << count << endl;int count_if = count_if(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; });cout << "偶数的个数:" << count_if << endl;
}

🔄 修改算法

void demonstrateModifyingAlgorithms() {vector<int> vec{1, 2, 3, 4, 5};vector<int> dest(vec.size());// 1. 复制copy(vec.begin(), vec.end(), dest.begin());// 条件复制vector<int> even_nums;copy_if(vec.begin(), vec.end(), back_inserter(even_nums), [](int x) { return x % 2 == 0; });// 2. 变换vector<int> squares(vec.size());transform(vec.begin(), vec.end(), squares.begin(), [](int x) { return x * x; });// 两个序列的变换vector<int> vec2{6, 7, 8, 9, 10};vector<int> sums(vec.size());transform(vec.begin(), vec.end(), vec2.begin(), sums.begin(),[](int a, int b) { return a + b; });// 3. 填充vector<int> filled(10);fill(filled.begin(), filled.end(), 42);// 生成vector<int> generated(10);int counter = 0;generate(generated.begin(), generated.end(), [&counter]() { return ++counter; });// 4. 替换vector<int> replaced = vec;replace(replaced.begin(), replaced.end(), 3, 99);  // 把3替换为99replace_if(replaced.begin(), replaced.end(), [](int x) { return x % 2 == 0; }, 0);   // 偶数替换为0// 5. 删除vector<int> removed{1, 2, 3, 2, 4, 2, 5};auto new_end = remove(removed.begin(), removed.end(), 2);  // 移除所有2removed.erase(new_end, removed.end());  // 真正删除// 或者使用erase-remove idiomremoved.erase(remove(removed.begin(), removed.end(), 4), removed.end());
}

📊 排序和相关算法

void demonstrateSortingAlgorithms() {vector<int> vec{3, 1, 4, 1, 5, 9, 2, 6, 5, 3};// 1. 完全排序sort(vec.begin(), vec.end());  // 升序sort(vec.begin(), vec.end(), greater<int>());  // 降序// 自定义比较函数vector<string> names{"Alice", "Bob", "Charlie", "David"};sort(names.begin(), names.end(), [](const string& a, const string& b) {return a.length() < b.length();  // 按长度排序});// 2. 部分排序vector<int> partial{3, 1, 4, 1, 5, 9, 2, 6, 5, 3};partial_sort(partial.begin(), partial.begin() + 3, partial.end());  // 只排序前3个最小的// 3. nth_element(快速选择)vector<int> nth_vec{3, 1, 4, 1, 5, 9, 2, 6, 5, 3};nth_element(nth_vec.begin(), nth_vec.begin() + 5, nth_vec.end());cout << "第5小的元素:" << nth_vec[5] << endl;// 4. 堆操作vector<int> heap{3, 1, 4, 1, 5, 9, 2, 6};make_heap(heap.begin(), heap.end());  // 建立最大堆heap.push_back(10);push_heap(heap.begin(), heap.end());  // 添加元素到堆pop_heap(heap.begin(), heap.end());   // 移除堆顶heap.pop_back();sort_heap(heap.begin(), heap.end());  // 堆排序// 5. 集合操作(需要有序序列)vector<int> set1{1, 2, 3, 4, 5};vector<int> set2{3, 4, 5, 6, 7};vector<int> result;// 并集set_union(set1.begin(), set1.end(), set2.begin(), set2.end(),back_inserter(result));result.clear();// 交集set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),back_inserter(result));result.clear();// 差集set_difference(set1.begin(), set1.end(), set2.begin(), set2.end(),back_inserter(result));
}

🎯 容器选择指南

📊 性能对比表

操作vectordequelistmapunordered_map
随机访问O(1)O(1)O(n)O(log n)O(1)平均
头部插入O(n)O(1)O(1)O(log n)O(1)平均
尾部插入O(1)摊销O(1)O(1)O(log n)O(1)平均
中间插入O(n)O(n)O(1)O(log n)N/A
查找O(n)O(n)O(n)O(log n)O(1)平均
内存局部性最好中等中等

🎯 选择建议

// 1. 需要频繁随机访问 → vector
vector<int> data;
cout << data[100] << endl;  // O(1)访问// 2. 需要频繁头尾操作 → deque
deque<int> queue;
queue.push_front(1);
queue.push_back(2);// 3. 需要频繁中间插入删除 → list
list<int> timeline;
auto it = timeline.begin();
advance(it, 10);
timeline.insert(it, new_event);  // O(1)插入// 4. 需要有序存储和查找 → map/set
map<string, int> scores;
auto range = scores.equal_range("Alice");  // 范围查询// 5. 需要快速查找,不关心顺序 → unordered_map/unordered_set
unordered_map<string, int> cache;
if (cache.find("key") != cache.end()) {  // O(1)查找// 处理缓存命中
}

🎯 面试高频考点

🔥 经典面试题

1. vector的扩容机制?
void demonstrateVectorGrowth() {vector<int> v;cout << "初始容量:" << v.capacity() << endl;for (int i = 0; i < 10; ++i) {v.push_back(i);cout << "大小:" << v.size() << ", 容量:" << v.capacity() << endl;}// 通常按1.5或2的倍数增长// 扩容时:分配新空间 → 复制元素 → 释放旧空间
}
2. map和unordered_map的区别?
"map基于红黑树实现,有序,O(log n)操作;
unordered_map基于哈希表,无序,O(1)平均操作。
选择依据:需要有序或范围查询用map,
只需要快速查找用unordered_map。"
3. 迭代器失效的情况?
void demonstrateIteratorInvalidation() {vector<int> v{1, 2, 3, 4, 5};// 1. vector扩容导致失效auto it1 = v.begin();v.push_back(6);  // 可能扩容,it1失效// 2. 删除元素导致失效auto it2 = v.begin() + 2;v.erase(it2);  // it2及其后面的迭代器失效// 3. list删除不影响其他迭代器list<int> lst{1, 2, 3, 4, 5};auto lst_it1 = lst.begin();auto lst_it2 = next(lst_it1);lst.erase(lst_it1);  // 只有lst_it1失效,lst_it2仍有效
}
4. STL算法的时间复杂度?
"sort: O(n log n)
find: O(n)
binary_search: O(log n) (需要有序)
lower_bound/upper_bound: O(log n)
make_heap: O(n)
push_heap/pop_heap: O(log n)"

🚀 实际应用案例

📝 LRU缓存实现

#include <unordered_map>
#include <list>class LRUCache {
private:int capacity;list<pair<int, int>> cache;  // 双向链表存储键值对unordered_map<int, list<pair<int, int>>::iterator> map;  // 哈希表存储迭代器public:LRUCache(int cap) : capacity(cap) {}int get(int key) {auto it = map.find(key);if (it == map.end()) {return -1;  // 未找到}// 移动到头部cache.splice(cache.begin(), cache, it->second);return it->second->second;}void put(int key, int value) {auto it = map.find(key);if (it != map.end()) {// 更新值并移动到头部it->second->second = value;cache.splice(cache.begin(), cache, it->second);return;}if (cache.size() >= capacity) {// 删除尾部元素int last_key = cache.back().first;cache.pop_back();map.erase(last_key);}// 在头部插入新元素cache.emplace_front(key, value);map[key] = cache.begin();}
};

🎯 单词频率统计

#include <sstream>
#include <algorithm>class WordCounter {
public:map<string, int> countWords(const string& text) {map<string, int> wordCount;istringstream iss(text);string word;while (iss >> word) {// 转换为小写transform(word.begin(), word.end(), word.begin(), ::tolower);// 移除标点符号word.erase(remove_if(word.begin(), word.end(), ::ispunct), word.end());if (!word.empty()) {wordCount[word]++;}}return wordCount;}vector<pair<string, int>> getTopWords(const map<string, int>& wordCount, int n) {vector<pair<string, int>> words(wordCount.begin(), wordCount.end());// 按频率降序排序sort(words.begin(), words.end(), [](const auto& a, const auto& b) {return a.second > b.second;});if (words.size() > n) {words.resize(n);}return words;}
};

🎉 课时总结

通过本课时的学习,我们全面掌握了STL的核心内容:

  • 容器掌握:理解了各种容器的特性和适用场景
  • 迭代器应用:学会了迭代器的使用技巧和注意事项
  • 算法运用:掌握了常用算法的应用和性能特点
  • 性能分析:了解了时间复杂度和内存使用特点
  • 实战应用:通过案例学会了STL在实际项目中的应用

STL是C++编程的利器,熟练掌握STL不仅能提高编程效率,还能写出更加安全、高效的代码。在面试和实际开发中,STL的重要性不言而喻。

下一课时,我们将学习C++的内存管理和智能指针,了解如何写出更加安全的C++代码。

💡 最佳实践:

  • 优先使用STL算法而非手写循环
  • 选择合适的容器,避免性能瓶颈
  • 注意迭代器失效问题
  • 善用lambda表达式简化代码
  • 利用auto关键字提高代码可读性
http://www.dtcms.com/a/449175.html

相关文章:

  • 做网站有什么关于财务的问题网络设计工作
  • P9751 [CSP-J 2023] 旅游巴士
  • 宠物用品网站开发背景网站推广设计
  • MySql复习及面试题学习
  • .NET周刊【9月第2期 2025-09-14】
  • 秦皇岛企业网站建设wordpress 悬浮音乐
  • 日语学习-日语知识点小记-进阶-JLPT-N1阶段应用练习(6):语法 +考え方19+2022年7月N1
  • 【Linux指南】gdb进阶技巧:断点高级玩法与变量跟踪实战
  • 跨平台游戏引擎 Axmol-2.9.0 发布
  • 金融 - neo4j、Graph Data Science 安装
  • c 可以做网站吗梧州seo排名
  • LuaC API知识点汇总
  • mysql学习--DCL
  • 开源 C++ QT QML 开发(七)自定义控件--仪表盘
  • 论坛开源网站源码网站建设实验总结报告
  • Ansible实战:VMware下K8s自动化部署指南
  • Ansible(三)—— 使用Ansible自动化部署LNMP环境实战指南
  • 【深度学习新浪潮】有没有可能设计出一种统一架构,可以同时处理图像理解的各种下游任务?
  • 介绍一下什么是RabbitMQ的发送者可靠性?
  • 网站后台管理页面模板北京企业建网站定制价格
  • AI编辑器(二) ---调用模型的fim功能
  • UniApp 自定义导航栏适配指南:微信小程序胶囊遮挡、H5 与 App 全端通用方案
  • 数据结构其一 线性表
  • 2025年--Lc164--H14.最长公共前缀(数组和字符串)--Java版
  • 网站html有了怎么建设网站钉钉小程序开发
  • Linux基本指令(2)
  • 从工具到中枢:2025 年 AI 重构实体经济的实践图景
  • 虚幻基础:攻击 与 受击 之间的联动
  • 如何在不降低画质的前提下缩小图片体积?附实操方案
  • 个人网站注册费用互联网广告价格