容器总结篇
·
C++ 标准库中的容器类是日常开发的核心工具,它们各自有不同的底层实现和适用场景。下面我会按序列式容器、容器适配器、关联式容器三大类来梳理这些容器的核心特点:
一、序列式容器(关注元素的存储顺序)
序列式容器的元素按插入顺序排列,访问方式主要依赖位置(索引或迭代器)。
1. vector(动态数组)
- 底层实现:连续内存空间的动态数组(内存不够时会重新分配更大的空间并复制元素)。
- 核心特点:
- 支持随机访问(通过
[]或at(),时间复杂度 O (1))。 - 尾部插入 / 删除元素高效(O (1)),中间 / 头部插入 / 删除低效(需要移动大量元素,O (n))。
- 内存连续,缓存友好,适合频繁访问元素的场景。
- 支持随机访问(通过
- 适用场景:需要频繁随机访问、尾部操作多的场景(如存储列表数据、动态数组)。
2. deque(双端队列)
- 底层实现:分段连续的内存块(由一个 "中控器" 管理多个固定大小的数组)。
- 核心特点:
- 支持双端高效操作(头部和尾部插入 / 删除都是 O (1))。
- 随机访问效率比
vector略低(需要先找对应内存块,再访问元素,O (1) 但常数更大)。 - 内存不连续但分段连续,避免
vector扩容时的大量复制。
- 适用场景:需要频繁在两端操作的场景(如实现队列、滑动窗口)。
3. list(双向链表)
- 底层实现:双向链表(每个节点包含数据、前驱指针、后继指针)。
- 核心特点:
- 不支持随机访问(访问元素需从头部 / 尾部遍历,O (n))。
- 任意位置插入 / 删除高效(只需修改指针,O (1),前提是已找到位置)。
- 内存不连续,缓存不友好,空间开销比数组大(需存储指针)。
- 适用场景:频繁在中间位置插入 / 删除元素的场景(如链表操作、频繁修改的列表)。
4. forward_list(单向链表)
- 底层实现:单向链表(每个节点只包含数据和后继指针)。
- 核心特点:
- 比
list更节省空间(少一个前驱指针),但只能单向遍历。 - 同样不支持随机访问,任意位置插入 / 删除高效(O (1),需找到前驱节点)。
- 比
- 适用场景:内存受限,且只需单向遍历、频繁修改的场景(功能类似
list但更轻量)。
二、容器适配器(基于其他容器封装的特殊功能容器)
适配器不直接存储数据,而是通过封装底层容器(如vector/deque/list)提供特定接口。
1. stack(栈)
- 底层依赖:默认基于
deque实现,也可指定vector或list(通过模板参数stack<T, Container>)。 - 核心特点:
- 遵循LIFO(后进先出) 原则,只能访问栈顶元素。
- 提供
push()(入栈)、pop()(出栈)、top()(访问栈顶)操作,无迭代器。
- 适用场景:需要栈结构的场景(如表达式求值、递归模拟、括号匹配)。
2. queue(队列)
- 底层依赖:默认基于
deque实现,也可指定list(不能用vector,因vector头部删除低效)。 - 核心特点:
- 遵循FIFO(先进先出) 原则,只能访问队头和队尾元素。
- 提供
push()(入队)、pop()(出队)、front()(队头)、back()(队尾)操作,无迭代器。
- 适用场景:需要队列结构的场景(如广度优先搜索、任务调度)。
三、关联式容器(关注元素的查找和唯一性)
关联式容器的元素按 "键"(key)组织,核心功能是高效查找(区别于序列式容器的 "按位置访问")。
1. set(有序集合)
- 底层实现:通常是红黑树(一种平衡二叉搜索树)。
- 核心特点:
- 存储唯一的元素(键即值,不允许重复),且元素自动按升序排序(可自定义比较器)。
- 插入、删除、查找效率为 O (log n)(红黑树的平衡特性保证)。
- 支持范围查找(如
lower_bound()/upper_bound())。
- 适用场景:需要去重且元素有序的场景(如存储唯一 ID 并按顺序遍历)。
2. unordered_set(无序集合)
- 底层实现:哈希表(通过哈希函数映射到桶,解决哈希冲突)。
- 核心特点:
- 存储唯一的元素,但无序(不支持排序相关操作)。
- 插入、删除、查找平均效率为 O (1)(哈希函数均匀时),最坏 O (n)(哈希冲突严重)。
- 不支持范围查找,空间开销比
set大(需存储哈希表结构)。
- 适用场景:需要快速去重和查找,且不关心元素顺序的场景(如判断元素是否存在)。
3. map(有序映射)
- 底层实现:通常是红黑树,键值对(key-value)结构,键唯一。
- 核心特点:
- 存储键值对,键唯一且自动按升序排序(可自定义比较器)。
- 通过键查找值的效率为 O (log n),支持根据键的范围遍历。
- 可通过
[]或at()直接访问键对应的值(若键不存在,[]会插入默认值)。
- 适用场景:需要键值对映射且键有序的场景(如字典、配置表)。
4. unordered_map(无序映射)
- 底层实现:哈希表,键值对结构,键唯一。
- 核心特点:
- 存储键值对,键唯一但无序。
- 通过键查找值的平均效率为 O (1),最坏 O (n)。
- 同样支持
[]访问,空间开销比map大。
- 适用场景:需要快速键值查找且不关心键顺序的场景(如缓存、计数统计)。
总结:选择容器的核心依据
- 是否需要随机访问?→ 选
vector/deque(序列式)。 - 是否需要频繁插入删除?→ 中间操作选
list,两端操作选deque。 - 是否需要栈 / 队列特性?→ 直接用
stack/queue适配器。 - 是否需要去重或键值映射?→ 有序选
set/map,追求速度无序选unordered_*。
理解它们的底层实现(数组 / 链表 / 红黑树 / 哈希表),就能快速记住各自的优缺点和适用场景了。
更多推荐


所有评论(0)