C++ STL 标准模板库完全指南:从容器到迭代器
2026/5/9 0:09:17 网站建设 项目流程

引言

在C++编程中,标准模板库是不可或缺的核心组成部分。无论你是参加算法竞赛、开发大型项目,还是准备技术面试,STL都能极大地提升你的开发效率。

STL发展历程中的几个重要版本:

版本开发者/应用场景特点
HP版本惠普公司原始开发是STL的原始实现,后被纳入C++标准
SGI版本Linux系统常用实现开源实现,被GCC编译器采用
PJ版本Visual Studio配套实现Windows平台主流实现

今天我们重点讲解的是在实际开发中最常用的容器——vectorlist,以及配套的迭代器、算法等核心组件。


第一部分:STL的核心组成

一、STL的四大组件

组件作用举例
容器存储数据的数据结构vectorlistmapset
迭代器统一访问容器元素的接口begin()end()
算法通用的数据处理函数sortfindcopy
仿函数行为类似函数的对象greaterless

二、迭代器(Iterator)

迭代器是面向对象化的指针,支持解引用、移动等操作,是连接容器与算法的桥梁。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> arr = {1, 2, 3, 4, 5}; // 迭代器的基本使用 vector<int>::iterator it = arr.begin(); cout << "第一个元素: " << *it << endl; // 遍历所有元素 for (it = arr.begin(); it != arr.end(); ++it) { cout << *it << " "; } cout << endl; return 0; }

三、算法(Algorithm)

算法库提供了大量常用操作,直接调用即可,无需重复造轮子。

分类算法函数功能
排序sort()排序
查找find()查找元素
拷贝copy()复制元素
删除remove()删除元素
统计count()计数
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> arr = {5, 2, 8, 1, 9, 3}; // 排序(默认升序) sort(arr.begin(), arr.end()); // 结果:1 2 3 5 8 9 // 降序排序 sort(arr.begin(), arr.end(), greater<int>()); // 结果:9 8 5 3 2 1 return 0; }

第二部分:vector容器详解

一、vector的底层结构

vector是动态数组,在内存中开辟连续空间存储元素。其底层由三个关键指针管理:

指针含义
start堆空间首地址
finish最后一个元素的后继地址(决定size)
end_of_storage空间容量末尾地址(决定capacity)

重要概念:

  • size():实际存储的元素个数

  • capacity():预分配的空间大小(size <= capacity

二、vector的扩容机制

当空间不足时,vector会自动扩容(通常按2倍或1.5倍增长)。

#include <iostream> #include <vector> using namespace std; int main() { vector<int> arr; cout << "初始: size=" << arr.size() << ", capacity=" << arr.capacity() << endl; for (int i = 0; i < 10; i++) { arr.push_back(i); cout << "push_back(" << i << "): size=" << arr.size() << ", capacity=" << arr.capacity() << endl; } return 0; }

扩容过程的影响:

  • 存储对象时:扩容需要逐个迁移对象并调用拷贝构造函数,性能开销大

  • 存储指针时:仅需迁移指针地址,性能更优(但需注意内存释放问题)

三、vector的初始化方式

#include <iostream> #include <vector> using namespace std; int main() { // 1. 默认构造 vector<int> v1; // 2. 指定大小 vector<int> v2(10); // 10个元素,值为0 vector<int> v3(10, 5); // 10个元素,值都为5 // 3. 列表初始化(C++11) vector<int> v4 = {1, 2, 3, 4, 5}; vector<int> v5{1, 2, 3, 4, 5}; // 4. 拷贝构造 vector<int> v6(v4); // 5. 迭代器范围构造 vector<int> v7(v4.begin(), v4.end()); return 0; }

四、vector的元素访问方式

访问方式语法边界检查效率
下标运算符arr[i]❌ 无检查最高
at()方法arr.at(i)✅ 抛出异常较高
front()arr.front()空容器未定义
back()arr.back()空容器未定义
data()arr.data()返回底层数组指针
#include <iostream> #include <vector> #include <stdexcept> using namespace std; int main() { vector<int> arr = {10, 20, 30, 40, 50}; // 下标访问(无边界检查) cout << arr[0] << endl; // 10 // arr[10] = 100; // 越界,未定义行为 // at()方法(有边界检查) try { cout << arr.at(2) << endl; // 30 cout << arr.at(10) << endl; // 抛出out_of_range异常 } catch (const out_of_range& e) { cout << "越界: " << e.what() << endl; } // 首尾元素 cout << "第一个元素: " << arr.front() << endl; // 10 cout << "最后一个元素: " << arr.back() << endl; // 50 return 0; }

五、vector的遍历方式

#include <iostream> #include <vector> using namespace std; int main() { vector<int> arr = {1, 2, 3, 4, 5}; // 方式1:下标遍历 cout << "下标遍历: "; for (size_t i = 0; i < arr.size(); i++) { cout << arr[i] << " "; } cout << endl; // 方式2:迭代器遍历 cout << "迭代器遍历: "; for (vector<int>::iterator it = arr.begin(); it != arr.end(); ++it) { cout << *it << " "; } cout << endl; // 方式3:范围for循环(C++11) cout << "范围for(值传递): "; for (auto x : arr) { // 拷贝每个元素 cout << x << " "; } cout << endl; // 方式4:范围for(引用传递,避免拷贝) cout << "范围for(引用传递): "; for (const auto& x : arr) { // 只读,不拷贝 cout << x << " "; } cout << endl; // 修改元素需要引用 for (auto& x : arr) { x *= 2; } return 0; }

效率对比:

  • 值传递for (auto x : arr):每次迭代都会拷贝元素,效率低

  • 引用传递for (auto& x : arr):不拷贝,效率高

  • const引用for (const auto& x : arr):只读场景,效率高且语义明确

六、vector的容量管理

#include <iostream> #include <vector> using namespace std; int main() { vector<int> arr; // 预分配容量(避免频繁扩容) arr.reserve(100); cout << "reserve后: capacity=" << arr.capacity() << endl; // 添加元素 for (int i = 0; i < 50; i++) { arr.push_back(i); } cout << "size=" << arr.size() << ", capacity=" << arr.capacity() << endl; // 释放多余内存 arr.shrink_to_fit(); cout << "shrink_to_fit后: capacity=" << arr.capacity() << endl; return 0; }
方法作用说明
reserve(n)预分配容量避免频繁扩容,不改变size
shrink_to_fit()释放多余内存将capacity缩小到size
clear()清空元素size变为0,capacity不变

七、vector的插入与删除

#include <iostream> #include <vector> using namespace std; int main() { vector<int> arr = {1, 2, 3, 4, 5}; // 尾部操作(高效,O(1)) arr.push_back(6); // 尾部插入 arr.pop_back(); // 尾部删除 // 中间操作(低效,O(n)) arr.insert(arr.begin() + 2, 100); // 在位置2插入100 arr.erase(arr.begin() + 3); // 删除位置3的元素 // 遍历 for (int x : arr) { cout << x << " "; } cout << endl; return 0; }

复杂度总结:

操作时间复杂度说明
push_back()/pop_back()O(1)尾部操作,高效
insert()/erase()(中间)O(n)需要移动元素,低效

第三部分:迭代器详解

一、迭代器的基本使用

#include <iostream> #include <vector> using namespace std; int main() { vector<int> arr = {10, 20, 30, 40, 50}; // 正向迭代器 cout << "正向遍历: "; for (vector<int>::iterator it = arr.begin(); it != arr.end(); ++it) { cout << *it << " "; } cout << endl; // 只读迭代器 cout << "只读遍历: "; for (vector<int>::const_iterator it = arr.cbegin(); it != arr.cend(); ++it) { cout << *it << " "; // *it = 100; // 错误!const_iterator不能修改 } cout << endl; // 反向迭代器 cout << "反向遍历: "; for (vector<int>::reverse_iterator it = arr.rbegin(); it != arr.rend(); ++it) { cout << *it << " "; } cout << endl; return 0; }

二、迭代器类型总结

迭代器类型获取方式可读可写方向
iteratorbegin()/end()正向
const_iteratorcbegin()/cend()正向
reverse_iteratorrbegin()/rend()反向

三、迭代器失效问题

#include <iostream> #include <vector> using namespace std; int main() { vector<int> arr = {1, 2, 3, 4, 5}; // 获取迭代器 auto it = arr.begin() + 2; // 指向元素3 cout << "*it = " << *it << endl; // 插入操作可能导致迭代器失效 arr.insert(arr.begin(), 0); // 头部插入,可能导致所有迭代器失效 // 危险!it可能已经失效 // cout << "*it = " << *it << endl; // 重新获取迭代器 it = arr.begin() + 3; cout << "重新获取后: *it = " << *it << endl; return 0; }

迭代器失效场景:

  • 插入元素导致扩容时,所有迭代器失效

  • 删除元素后,被删除位置之后的迭代器失效


第四部分:list容器详解

一、list的底层结构

list是双向链表,节点在内存中不连续,通过指针连接。

// list节点的简化结构 template<typename T> struct ListNode { T data; // 数据域 ListNode* prev; // 前驱指针 ListNode* next; // 后继指针 }; // 带哨兵节点的双向链表 // head指向头节点(哨兵),size记录元素个数
list内存布局(逻辑结构): ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ 节点1 │◄──►│ 节点2 │◄──►│ 节点3 │◄──►│ 节点4 │ │ data │ │ data │ │ data │ │ data │ └──────┘ └──────┘ └──────┘ └──────┘ ↑ ↑ └──────────────┐ ┌──────────────────┘ ▼ ▼ ┌──────────┐ │ 哨兵节点 │ └──────────┘

二、list的基本操作

#include <iostream> #include <list> using namespace std; int main() { // 初始化 list<int> lst = {1, 2, 3, 4, 5}; // 插入操作(高效,O(1)) lst.push_back(6); // 尾部插入 lst.push_front(0); // 头部插入 // 删除操作(高效,O(1)) lst.pop_back(); // 尾部删除 lst.pop_front(); // 头部删除 // 访问(只能访问首尾) cout << "第一个元素: " << lst.front() << endl; cout << "最后一个元素: " << lst.back() << endl; // ❌ list不支持下标访问 // cout << lst[2] << endl; // 错误! // 遍历(使用迭代器或范围for) cout << "遍历: "; for (int x : lst) { cout << x << " "; } cout << endl; return 0; }

三、list vs vector

特性vectorlist
底层结构动态数组(连续内存)双向链表(非连续)
随机访问✅ O(1)❌ O(n)
中间插入/删除❌ O(n)✅ O(1)
尾部插入/删除✅ O(1)(扩容时O(n))✅ O(1)
内存占用较少(无指针开销)较大(前后指针)
适用场景频繁访问、尾部操作频繁中间插入删除

四、list的特殊操作

#include <iostream> #include <list> #include <algorithm> using namespace std; int main() { list<int> lst = {5, 2, 8, 1, 3, 2, 5, 2}; // list专属排序(不能用标准库的sort) lst.sort(); // 升序排序 // lst.sort(greater<int>()); // 降序排序 // 去重(必须先排序) lst.unique(); // 删除相邻重复元素 // 删除指定值的所有元素 lst.remove(2); // 删除所有值为2的元素 // 合并两个有序list list<int> lst2 = {10, 20, 30}; lst.merge(lst2); // lst2被清空,元素合并到lst // 反转 lst.reverse(); for (int x : lst) { cout << x << " "; } cout << endl; return 0; }

第五部分:关联容器(set/map)

一、set容器(集合)

set中的元素唯一且自动排序,底层基于红黑树实现。

#include <iostream> #include <set> using namespace std; int main() { vector<int> arr = {5, 2, 8, 1, 5, 2, 9, 3}; // 使用set去重 set<int> s; for (int x : arr) { s.insert(x); } cout << "去重后: "; for (int x : s) { cout << x << " "; } cout << endl; // 输出:1 2 3 5 8 9(自动排序) // 查找元素 if (s.find(5) != s.end()) { cout << "5存在" << endl; } return 0; }

二、map容器(映射)

map存储键值对,键唯一且自动排序。

#include <iostream> #include <map> using namespace std; int main() { vector<int> arr = {1, 2, 3, 2, 1, 3, 4, 2, 1}; // 统计每个元素出现的次数 map<int, int> freq; for (int x : arr) { freq[x]++; // 使用[]操作符 } // 遍历map for (const auto& kv : freq) { cout << kv.first << "出现" << kv.second << "次" << endl; } return 0; }

三、unordered_set/unordered_map

无序版本,底层基于哈希表实现,查找更快(O(1)),但不保证顺序。

容器底层结构有序性查找复杂度
set/map红黑树有序O(log n)
unordered_set/unordered_map哈希表无序O(1) 平均
#include <iostream> #include <unordered_set> using namespace std; int main() { unordered_set<int> us = {5, 2, 8, 1, 9}; // 顺序不确定 for (int x : us) { cout << x << " "; } cout << endl; return 0; }

总结

一、容器特性对比

容器底层随机访问中间插入/删除适用场景
vector动态数组✅ O(1)❌ O(n)频繁访问、尾部操作
list双向链表❌ O(n)✅ O(1)频繁中间插入删除
deque双端队列✅ O(1)两端O(1)双端操作
set/map红黑树插入/查找O(log n)有序唯一集合
unordered_set/unordered_map哈希表插入/查找O(1)快速查找、去重

二、迭代器类型

迭代器获取方式支持操作
iteratorbegin()/end()读+写
const_iteratorcbegin()/cend()只读
reverse_iteratorrbegin()/rend()反向遍历

三、vector常用操作速查

操作方法复杂度
尾部插入push_back()O(1)
尾部删除pop_back()O(1)
中间插入insert()O(n)
中间删除erase()O(n)
访问元素[]/at()O(1)
大小size()O(1)
容量capacity()O(1)
预分配reserve()O(n)

四、list常用操作速查

操作方法复杂度
头部插入push_front()O(1)
头部删除pop_front()O(1)
尾部插入push_back()O(1)
尾部删除pop_back()O(1)
排序sort()O(n log n)
去重unique()O(n)
合并merge()O(n)

STL是C++标准库的核心,掌握STL能够极大地提升开发效率。

STL使用三步法:

  1. 掌握基本使用方法

  2. 熟练运用各类容器和算法

  3. 理解源码实现并实现功能扩展

学习建议:

  1. 优先级:vector>list>map>unordered_map

  2. 迭代器遍历时注意引用传递避免拷贝

  3. 使用reserve()预分配容量避免频繁扩容

  4. 优先使用emplace_back()替代push_back()减少拷贝

  5. 根据场景选择合适的关联容器(有序选map,无序选unordered_map

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询