
目录前言一、STL 六大组件回顾二、vector 容器详解三、迭代器分类四、list 容器详解五、map 容器详解六、总结前言STL 是 C 开发的核心利器几乎所有项目都会用到容器、迭代器与算法。相比于 C 语言手动实现顺序表、链表、哈希结构STL 提供了一套标准化、高复用、高效率的通用组件大幅提升开发效率。本文结合实战代码、底层原理、避坑细节完整讲解 STL 六大核心组成重点剖析vector、list、map、multimap常用容器用法、迭代器分类、仿函数特性适合新手学习、面试复盘。一、STL 六大组件回顾STL 标准组成分为六大模块相互配合实现泛型编程容器存储数据vector、list、map、set 等迭代器容器通用“泛型指针”统一遍历方式算法排序、查找、去重等通用算法仿函数重载()的类/结构体可像函数一样调用配接器基于容器改造栈、队列、优先队列配置器负责内存分配vector 内存池底层依赖它不同平台 STL Linux 使用 SGI STLVisual Studio 使用 PJ STL。二、vector 容器详解vector是动态数组类似 C 语言的顺序表支持随机访问。2.1 vector 的三种访问方式ar[i]可以表示三种情况数组名、指针、对象名重载了operator[]。int main() { std::vectorint ar {12, 23, 34, 45, 56, 67, 78, 89, 90, 11}; // 1. front() / back()首尾元素 cout ar.front() endl; // 第一个元素 cout ar.back() endl; // 最后一个元素 // 2. at()带边界检查 for (int i 0; i ar.size(); i) { cout ar.at(i) endl; } // 3. operator[]不带边界检查 for (int i 0; i ar.size(); i) { cout ar[i] endl; ar.operator[](i); // 等价写法 } }2.2 at() vs operator[] 的区别方法越界行为返回类型适用场景ar.at(i)一定会检查越界越界抛出std::out_of_range异常引用需要安全访问时ar[i]不检查越界行为未定义引用确定不越界时性能更高不同平台表现平台at(i)ar[i]越界时Windows VSDebug抛异常断言中断检查越界Windows VSRelease抛异常不检查未定义行为Linux g抛异常不检查可能崩溃或乱值关键点VS 在 Debug 模式下operator[]也会检查越界断言但 Release 模式下不检查。不能依赖 VS Debug 的行为写代码因为换到 Linux 或其他编译器就没有这个保护了。2.3 范围 for 循环int main() { std::vectorint ar {12, 23, 34, 45, 56, 67, 78, 89, 90, 100}; // 值拷贝效率低类类型时尤其明显 for (auto x : ar) { printf(%5d, x); } // 引用推荐不拷贝 for (auto x : ar) { printf(%5d, x); } // const 引用只读 for (const auto x : ar) { printf(%5d, x); } }auto可以少一次拷贝推荐使用。2.4 迭代器遍历int main() { std::vectorint ar {12, 23, 34, 45, 56, 67, 78, 89, 90, 100}; std::vectorint::iterator it ar.begin(); std::vectorint::iterator end ar.end(); for (; it ! end; it) { cout *it endl; } // const 迭代器只读 std::vectorint::const_iterator cit; }2.5 reserve() vs resize()reserve(n)预留空间只改变capacity不改变size。std::vectorint ar; ar.reserve(10); cout ar.size(); // 0 cout ar.capacity(); // 10resize(n)设置容器大小同时改变size和capacity。std::vectorint ar; ar.resize(10); cout ar.size(); // 10 cout ar.capacity(); // 至少 10可能更大核心区别reserve只扩容不创建元素。size不变。resize扩容并创建元素。size变为n。2.6 vector 常用函数int main() { std::vectorint ar; ar.resize(10000); cout size: ar.size() endl; // 10000 cout capacity: ar.capacity() endl; // 至少 10000 // 删除区间 [begin2, end) ar.erase(ar.begin() 2, ar.end()); cout size: ar.size() endl; // 2 cout capacity: ar.capacity() endl; // 容量不变 // 收缩容量使 capacity size ar.shrink_to_fit(); cout size: ar.size() endl; // 2 cout capacity: ar.capacity() endl; // 2 }2.7 vector 类型别名templateclass T class vector { public: using value_type T; using reference T; using const_reference const T; using pointer T*; using const_pointer const T*; };三、迭代器分类迭代器类型特点支持的操作容器示例随机迭代器支持任意跳跃、-、、-、[]vector、deque双向迭代器一次走一步可前可后、--list、map、set正向迭代器只能单向向后hash_map、hash_set随机迭代器示例int main() { std::vectorint ivec {12, 23, 34, 45, 56}; std::vectorint::iterator it ivec.begin(); cout *it endl; // 12 cout *(it 3) endl; // 45 it 3; cout *it endl; // 45 it - 2; cout *it endl; // 34 }双向迭代器示例int main() { std::listint ilist {12, 23, 34, 45, 56}; std::listint::iterator it ilist.begin(); it; // 可以向前 it; it--; // 可以向后 }四、list 容器详解4.1 list 访问方式int main() { std::listint ilist {12, 23, 34, 45, 56}; // 1. 范围 for for (auto x : ilist) { cout x ; } // 2. 迭代器 for (auto it ilist.begin(); it ! ilist.end(); it) { cout *it ; } // 3. front/back cout ilist.front() endl; // 第一个元素 cout ilist.back() endl; // 最后一个元素 }4.2 list 插入int main() { std::listint mylist {1, 3, 5, 7, 9}; std::listint helist {2, 4, 6, 8, 10}; // 在开头插入 10 个 23 mylist.insert(mylist.begin(), 10, 23); // 在中间位置插入 auto it mylist.begin(); it; it; it; mylist.insert(it, helist.begin(), helist.end()); }4.3 list 拼接spliceint main() { std::listint mylist {1, 3, 5, 7, 9}; std::listint helist {2, 4, 6, 8, 10}; auto it mylist.begin(); mylist.splice(it, helist, helist.begin(), helist.end()); // helist 中的元素被移动到 mylist 中 }4.4 list 删除// remove按值删除 mylist.remove(45); // remove_if按条件删除 int x; cin x; mylist.remove_if([x](const int y) { return y x; });4.5 list 注意事项操作说明clear()删除所有元素size归 0表头节点保留头插/尾插都是 O(1) 效率erase按迭代器删除不能按值删除erase(end)❌ 不能删除 end会崩溃// 删除区间 [begin, end) mylist.erase(mylist.begin(), mylist.end());五、map 容器详解map是键值对容器key-value像字典一个唯一键对应一个值。5.1 map 基础操作int main() { std::mapint, std::string ismap; // key 不可重复 std::multimapint, std::string mismap; // key 可以重复 }5.2 std::pair 与 make_pairint main() { // 构造 pair std::pairint, std::string p1(12, apple); std::pairint, std::string p2 std::make_pair(12, banana); // 访问成员 cout p1.first p1.second endl; // C17 结构化绑定 auto [id, name] p1; cout id name endl; // pair 比较先比 first再比 second cout (p1 p2) endl; }5.3 给 map 插入元素int main() { std::mapint, std::string ismap { {12, zhangsan}, {23, lisi}, {34, wangwu}, {45, zhaoliu} }; // 四种插入方式 ismap.insert({100, beijing}); ismap.insert(std::pairint, std::string(78, henan)); ismap.insert(std::make_pair(56, guangzhou)); ismap.insert(std::mapint, std::string::value_type(67, yunnan)); // 遍历 for (auto xp : ismap) { cout xp.first xp.second endl; } }5.4 map 的 operator[] 行为int main() { std::mapint, std::string ismap { {12, zhangsan}, {23, lisi}, {34, wangwu} }; int key; while (cin key, key ! -1) { cout ismap[key] endl; // 行为 // 1. 去 map 里查找 key // 2. 如果有返回值的引用 // 3. 如果没有自动插入这个 key } }注意operator[]会在 key 不存在时自动插入慎用。5.5 map 实现计数器int main() { const int n 10000; std::vectorint ivec; ivec.reserve(n); srand(time(nullptr)); for (int i 0; i n; i) { ivec.push_back(rand() % 100); } // 统计数字出现次数 mapint, int countMap; for (auto num : ivec) { countMap[num]; // 核心一行代码完成统计 } for (auto pair : countMap) { cout pair.first pair.second endl; } }5.6 删除 map 元素// 方式1通过迭代器删除 auto it ismap.find(lisi); if (it ! ismap.end()) { ismap.erase(it); } // 方式2通过 key 删除 ismap.erase(zhaoliu);5.7 map 合并mergeint main() { std::mapint, char icmap1 {{1,a}, {3,b}, {5,c}}; std::mapint, char icmap2 {{2,d}, {4,e}, {3,f}, {6,g}}; icmap1.merge(icmap2); // 冲突的 key 不会被合并 }5.8 lower_bound / upper_bound函数作用lower_bound(key)返回第一个≥ key的元素upper_bound(key)返回第一个 key的元素auto it icmap.lower_bound(key); // 第一个 key auto it icmap.upper_bound(key); // 第一个 key5.9 equal_rangeauto it icmap.equal_range(key); // 返回一对迭代器 [first, second) // first lower_bound(key) // second upper_bound(key)5.10 multimap 用法int main() { std::multimapint, char icmap; for (int i 0; i 26; i) { icmap.insert({rand() % 10, i a}); } // 获取所有 key 为特定值的元素 auto it icmap.equal_range(key); for (auto i it.first; i ! it.second; i) { cout i-first i-second endl; } }5.11 按频度排序// 按数字出现次数升序打印 std::multimapint, int iimap; for (auto pair : countMap) { iimap.insert(make_pair(pair.second, pair.first)); } PrintMap(iimap); // 按次数从小到大输出六、总结知识点核心要点STL 六大组件容器、迭代器、算法、仿函数、配接器、配置器vector vs listvector 连续存储支持随机访问list 链表适合频繁插入删除at() vs operator[]at()抛异常安全operator[]不检查边界高效reserve vs resizereserve只扩容量size 不变resize同时扩容量和大小shrink_to_fit收缩容量使capacity size迭代器类型随机迭代器vector、双向迭代器list/map、正向迭代器hashmap 特点键值对存储key 唯一且自动排序operator[]会插入不存在的 keymultimapkey 可重复无operator[]pair存储两个值的结构体first和second成员结构化绑定C17auto [a, b] pair一键拆包lower_bound / upper_boundlower_bound找第一个 ≥ keyupper_bound找第一个 keyequal_range同时返回 lower_bound 和 upper_boundmap 实现计数器countMap[num]一行代码完成统计splicelist 专属O(1) 拼接两个链表remove / remove_iflist 按值/按条件删除元素