C++ 标准模板库(STL)中的容器根据其对内存的管理方式和数据组织形式,主要分为序列式容器(Sequence Containers)和关联式容器(Associative Containers),以及 C++11 引入的无序关联容器(Unordered Associative Containers)。
1. 序列式容器 (Sequence Containers)
1.std::vector (向量)
- 底层结构 :动态数组 (Dynamic Array)。
- 特点 :
- 内存连续分配,支持随机访问( O(1) )。
- 尾部插入/删除效率高(均摊O(1) ),但中间或头部插入/删除效率低( O(n) ,因为需要移动元素)。
- 当容量不足时,会重新分配一块更大的内存(通常是原来的 1.5 倍或 2 倍),并将旧数据拷贝过去,这可能导致迭代器失效。
- 适用场景:需要频繁随机访问,且主要在尾部进行增删操作的场景。
2.std::deque (双端队列)
- 底层结构 :分段连续空间(通常实现为"数组的数组"或"中控地图 + 缓冲区")。
- 特点 :
- 由一段段定长的连续空间组成,通过一个中控指针(map)来管理这些分段。
- 支持首尾两端的高效插入和删除( O(1) )。
- 支持随机访问( O(1) ),但比
vector稍慢,因为涉及两次指针跳转(先找段,再找段内偏移)。 - 内存不需要完全连续,扩容时只需分配新的分段,无需整体拷贝。
- 适用场景:需要频繁在首尾两端进行增删操作,且需要随机访问的场景。
3.std::list (链表)
- 底层结构 :双向链表 (Doubly Linked List)。
- 特点 :
- 内存不连续,每个节点包含数据域、前驱指针和后继指针。
- 不支持随机访问(访问第 n 个元素需 O(n) )。
- 在任意位置插入和删除元素效率极高( O(1) ,前提是已知位置迭代器),因为只需修改指针,无需移动元素。
- 额外内存开销较大(每个节点需存两个指针)。
- 适用场景:需要频繁在任意位置进行插入/删除,且不常进行随机访问的场景。
4.std::forward_list (单向链表)
- 底层结构 :单向链表 (Singly Linked List)。
- 特点 :
- 比
list更节省空间(每个节点只有一个后继指针)。 - 只能向前遍历,不支持反向迭代器。
- 插入/删除操作同样高效,但某些操作(如
insert之前)需要记录前驱节点,接口设计上略有不同。
- 比
5.std::array
- 底层结构 :固定大小数组。
- 特点 :
- 封装了原生数组,大小在编译期确定,不可改变。
- 内存连续,零开销抽象。
2. 关联式容器 (Associative Containers)
这类容器通过键值(Key)来检索元素,内部通常采用平衡二叉树结构,元素自动排序。
std::set/std::multisetstd::map/std::multimap- 底层结构 :红黑树 (Red-Black Tree) 。
- 红黑树是一种自平衡的二叉搜索树(BST)。
- 特点 :
- 所有操作(查找、插入、删除)的时间复杂度均为 O(logn) 。
- 元素会根据 Key 自动排序(默认升序)。
map存储pair<const Key, Value>,set存储Key。multi版本允许键值重复。- 迭代器失效规则相对宽松:插入节点通常不会导致其他节点的迭代器失效(除了被删除的节点)。
- 适用场景:需要元素有序,且对查找、插入、删除效率有稳定要求( O(logn) )的场景。
- 底层结构 :红黑树 (Red-Black Tree) 。
3. 无序关联容器 (Unordered Associative Containers)
C++11 引入,基于哈希表实现,不保证元素顺序,但平均效率更高。
std::unordered_set/std::unordered_multisetstd::unordered_map/std::unordered_multimap- 底层结构 :哈希表 (Hash Table) 。
- 具体实现通常为:数组 + 链表 (拉链法,Chaining)或 数组 + 开放寻址法(Open Addressing)。
- 主流实现(如 GCC)通常使用拉链法:一个桶数组(Bucket Array),每个桶指向一个链表(或红黑树,当链表过长时可能转为树以优化最坏情况,类似 Java HashMap),冲突的元素挂在链表上。
- 特点 :
- 平均查找、插入、删除时间复杂度为O(1) 。
- 最坏情况下(哈希冲突严重)退化为 O(n) 。
- 元素无序存储。
- 需要用户自定义哈希函数(对于非基本类型)。
- 适用场景:不需要元素有序,追求极致查找速度,且能接受最坏情况波动的场景。
- 底层结构 :哈希表 (Hash Table) 。
4. 容器适配器 (Container Adapters)
它们不是独立的容器,而是基于上述容器封装而成的特定数据结构。
-
std::stack(栈)- 默认底层容器 :
std::deque。 - 可选底层 :
std::vector或std::list。 - 特性:后进先出 (LIFO)。
- 默认底层容器 :
-
std::queue(队列)- 默认底层容器 :
std::deque。 - 可选底层 :
std::list(不能用vector,因为vector不支持高效的头部删除)。 - 特性:先进先出 (FIFO)。
- 默认底层容器 :
-
std::priority_queue(优先队列)- 默认底层容器 :
std::vector。 - 数据结构逻辑 :堆 (Heap)(通常是大顶堆)。
- 特性 :通过底层容器的
push_heap和pop_heap算法维持堆性质,队头始终是最大(或最小)元素。
- 默认底层容器 :
总结对比
| 容器 | 底层数据结构 | 随机访问 | 头部插入/删除 | 中间插入/删除 | 尾部插入/删除 | 查找复杂度 | 是否有序 |
|---|---|---|---|---|---|---|---|
| vector | 动态数组 | O(1) | O(n) | O(n) | O(1)* | O(n)/O(logn) | 否 |
| deque | 分段连续数组 | O(1) | O(1) | O(n) | O(1) | O(n) | 否 |
| list | 双向链表 | 不支持 | O(1) | O(1) | O(1) | O(n) | 否 |
| map/set | 红黑树 | 不支持 | O(log n) | O(log n) | O(log n) | O(log n) | 是 |
| unordered_map/set | 哈希表 | 不支持 | - | - | - | 平均O(1) | 否 |
注:vector 尾部插入在扩容时为O(n) ,但均摊复杂度为O(1) 。