序列容器(顺序存储元素)
- std::vector:动态数组,支持快速随机访问
- std::deque:双端队列,支持高效的首尾插入/删除。
- std::list:双向链表,支持高效插入/删除。
- std::forward_list:单向链表(C++11引入),内存开销更小。
- std::array:固定大小数组(C++11引入),编译时确定大小。
关联容器(基于键值存储,允许快速查找)
有序关联容器(元素按键排序):
无序关联容器(C++11引入,基于哈希表):
- std::unordered_set:哈希实现的唯一键集合。
- std::unordered_multiset:哈希实现的可重复键集合。
- std::unordered_map:哈希实现的键值对映射(键唯一)。
- std::unordered_multimap:哈希实现的可重复键映射。
容器适配器(基于其他容器封装)
- [std::stack:栈(LIFO 后进先出),默认基于deque。](#std::stack:栈(LIFO 后进先出),默认基于deque。)
- [std::queue:队列(FIFO 先进先出),默认基于deque](#std::queue:队列(FIFO 先进先出),默认基于deque)
- std::priority_queue:优先队列,元素按优先级排序,默认基于vector。
其他容器
std::vector 数据结构与内存管理
1. 底层结构
- 连续内存块:元素在内存中紧密排列
- 三指针逻辑 (典型实现):
begin_ptr→ 内存起始位置size_ptr→ 当前元素末尾(size())capacity_ptr→ 内存块末尾(capacity())
2. 插入操作
| 场景 | 操作步骤 | 时间复杂度 |
|---|---|---|
| 尾部空间充足 | 1. 在size_ptr处构造元素 2. size_ptr后移 |
O(1) |
| 空间不足需扩容 | 1. 分配新内存(容量:GCC×2 / MSVC×1.5) 2. 迁移数据(优先移动语义) 3. 释放旧内存 | 均摊 O(1) |
| 中间插入 | 1. 移动后续元素腾出空间 2. 构造新元素 | O(n) |
3. 删除操作
| 类型 | 操作步骤 | 时间复杂度 |
|---|---|---|
| 尾部删除 | 1. 销毁末尾元素 2. size_ptr前移 |
O(1) |
| 中间删除 | 1. 销毁目标元素 2. 向前移动后续元素覆盖空隙 | O(n) |
4. 关键特性
-
内存策略 :
-
扩容:指数增长(避免频繁重分配)
-
不自动缩容:
erase不释放内存 -
手动释放:
cppv.shrink_to_fit(); // 请求释放多余内存 vector<int>().swap(v); // 强制释放所有内存
-
-
迭代器失效 :
- 扩容或中间插入/删除导致迭代器失效
-
性能对比 :
操作 复杂度 适用性 随机访问 O(1) ★★★★★ 尾部操作 均摊 O(1) ★★★★★ 中间操作 O(n) ★☆☆☆☆
std::deque 核心知识点总结
一、基础概念与特性
- 容器类型
C++ STL 中的双端队列(double-ended queue) - 访问特性
支持随机访问 (通过operator[]或at()) - 动态扩展
两端插入/删除操作高效,时间复杂度为 **O(1)** - 底层实现
基于分段连续存储结构(多个固定大小的数组块 + 中央控制块)
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 默认分配器 | std::allocator<T> |
| 分段存储结构 | 由多个固定大小的数组块组成(典型块大小 512 bytes - 4KB) |
| 中央控制映射器 | 维护指向所有块的指针数组(动态扩容时重新分配) |
| 内存分配策略 | 插入时: - 两端:直接使用预留空间或分配新块 - 中间:移动元素 |
| 扩容机制 | 中央指针数组满时重新分配(通常翻倍) |
| 非连续内存 | 元素物理存储非连续,但逻辑连续 |
内存布局示例:
控制映射器: [ptr0, ptr1, ptr2, ...] | | | 块0: [a,b,c] 块1: [d,e,f] 块2: [g,h,i]
三、核心操作特性
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 头尾插入/删除 | O(1) | push_front()/pop_front() push_back()/pop_back() |
| 随机访问 | O(1) | operator[] 或 at() 直接访问元素 |
| 中间插入/删除 | O(n) | insert()/erase() 需移动元素 |
| 迭代器操作 | O(1) | 支持随机访问迭代器(++, --, +n 等) |
四、模板参数
cpp
template<
class T, // 元素类型
class Allocator = std::allocator<T> // 分配器类型
> class deque;
std::list 核心知识点总结
一、基础概念与特性
- 容器类型
C++ STL 中的双向链表容器 - 存储结构
每个元素存储在独立的节点中,节点包含:- 数据值
- 前驱节点指针
- 后继节点指针
- 迭代器特性
支持双向迭代器(可前向/后向遍历)
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 默认分配器 | std::allocator<T> |
| 节点内存分配 | 每个元素独立分配内存(包含数据+两个指针) |
| 分配触发时机 | push_back/push_front/insert 时分配新节点 |
| 内存释放时机 | pop_back/pop_front/erase 时立即释放节点 |
| 内存碎片 | 高频插入删除可能产生内存碎片 |
| 连续内存 | ❌ 元素在内存中非连续存储 |
节点结构示例:
cppstruct ListNode { T data; // 存储的元素值 ListNode* prev; // 前驱节点指针 ListNode* next; // 后继节点指针 };
三、核心操作特性
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 头尾插入/删除 | O(1) | push_front()/pop_front() push_back()/pop_back() |
| 任意位置插入 | O(1) | insert(iterator_pos, value)(只需修改相邻节点指针) |
| 任意位置删除 | O(1) | erase(iterator_pos)(只需修改相邻节点指针) |
| 元素查找 | O(n) | 必须从头/尾开始遍历 |
| 迭代器稳定性 | ✅ 稳定 | 插入/删除操作不会使其他迭代器失效(除被删除元素的迭代器) |
四、特殊成员函数
- 链表拼接
splice():将其他链表的元素移动到当前链表(O(1)时间复杂度)
// 将other链表的全部元素移动到当前链表末尾
mylist.splice(mylist.end(), otherlist);
std::forward_list 核心知识点总结
一、基础概念与特性
- 单向链表结构
C++11 引入的单向链表容器,每个节点包含数据值和指向下一节点的指针 - 最小化内存开销
相比std::list节省内存(每个节点少一个指针) - 迭代器特性
仅支持前向迭代器(不可反向遍历)
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 默认分配器 | std::allocator<T> |
| 节点结构 | { data, next_ptr }(仅含数据域和单向指针) |
| 内存分配 | 插入操作时动态分配新节点(如 push_front, insert_after) |
| 内存释放 | 删除操作立即释放节点内存(如 pop_front, erase_after) |
| 内存碎片 | 高频插入删除可能产生碎片(但比 std::list 碎片少 25%) |
节点结构示例:
cppstruct ForwardListNode { T data; // 存储的元素值 ForwardListNode* next; // 指向下一节点的指针 };
三、核心操作特性
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 头部插入 | O(1) | push_front() 在链表头插入新元素 |
| 指定位置后插入 | O(1) | insert_after(pos) 在迭代器 pos 后插入元素 |
| 头部删除 | O(1) | pop_front() 删除首元素 |
| 指定位置后删除 | O(1) | erase_after(pos) 删除 pos 后元素 |
| 元素查找 | O(n) | 必须从头节点开始顺序遍历 |
| 迭代器稳定性 | ✅ 稳定 | 插入/删除操作不影响其他迭代器(除被删元素的迭代器) |
四、特殊成员函数
- 首前迭代器
before_begin():返回首元素前的虚拟节点迭代器(用于首元素操作)
auto it = flist.before_begin();
flist.insert_after(it, 42); // 在链表头插入
std::array 核心知识点总结
一、基础概念与特性
- 固定大小数组容器
C++11 引入的静态连续数组容器,封装原生数组 - 内存分配方式
元素在栈内存 或全局/静态存储区分配(与原生数组相同) - 零额外开销
相比原生数组,不增加任何空间或时间开销(编译期确定大小)
二、模板参数与声明
cpp
template<
class T, // 元素类型
std::size_t N // 数组固定大小
> class array;
关联容器(基于键值存储,允许快速查找)
有序关联容器(元素按键排序):
std::set 核心知识点总结
一、基础概念与特性
- 有序关联容器
存储唯一键值(无重复元素)并自动按键排序 - 红黑树实现
基于红黑树(自平衡二叉搜索树)实现,保证操作效率 - 自动排序机制
元素始终按键升序排列 (默认std::less<Key>)
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 默认分配器 | std::allocator<Key> |
| 节点内存分配 | 每个元素独立分配内存(含数据+父/子指针+颜色标志) |
| 分配触发时机 | insert() 操作时动态分配新节点 |
| 内存释放时机 | erase() 操作时立即释放节点内存 |
| 内存布局 | 树形结构存储,节点间非连续内存 |
节点结构示例:
cppstruct Node { Node* parent; Node* left; Node* right; bool color; // 红黑树颜色标志 Key value; // 存储的元素值 };
三、核心操作特性
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 插入元素 | O(log n) | insert(key) 或 emplace(args) |
| 删除元素 | O(log n) | erase(key) 或 erase(iterator) |
| 查找元素 | O(log n) | find(key)/contains(key)(C++20) |
| 范围查询 | O(log n) | lower_bound()/upper_bound() 实现高效范围扫描 |
| 迭代器稳定性 | ✅ 稳定 | 插入/删除操作不影响其他迭代器(除被删元素的迭代器) |
四、模板参数
cpp
template<
class Key, // 元素类型(必须支持严格弱序比较)
class Compare = std::less<Key>, // 比较器(默认升序)
class Allocator = std::allocator<Key> // 内存分配器
> class set;
std::multiset 核心知识点总结
一、基础概念与特性
- 有序关联容器
存储可重复键值 的集合,元素自动按键排序
set是多了判断是否重复 - 红黑树实现
基于红黑树(自平衡二叉搜索树)实现 - 自动排序机制
元素始终按键升序排列 (默认std::less<Key>)
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 默认分配器 | std::allocator<Key> |
| 节点结构 | 每个节点包含: - 键值数据 - 父/子节点指针 - 红黑树颜色标志 |
| 内存分配 | insert() 操作时动态分配新节点 |
| 内存释放 | erase() 操作时立即释放节点内存 |
| 内存布局 | 树形结构存储,节点间非连续内存 |
| 内存占用 | 每个节点额外开销约 3 指针 + 1 bool(通常 16-32 字节) |
节点结构示例:
cppstruct Node { Node* parent; // 父节点指针 Node* left; // 左子节点指针 Node* right; // 右子节点指针 bool color; // 红黑树颜色标志 Key value; // 存储的元素值 };
三、核心操作特性
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 插入元素 | O(log n) | insert(key) 可重复插入相同键值 |
| 删除元素 | O(log n) | erase(key) 删除所有匹配键值;erase(iterator) 删除指定元素 |
| 元素计数 | O(log n) | count(key) 返回匹配键值的元素数量 |
| 范围查询 | O(log n) | equal_range(key) 获取相同键值元素的范围迭代器对 |
| 迭代器稳定性 | ✅ 稳定 | 插入/删除操作不影响其他迭代器 |
四、模板参数
cpp
template<
class Key, // 元素类型(必须支持严格弱序比较)
class Compare = std::less<Key>, // 比较器(默认升序)
class Allocator = std::allocator<Key> // 内存分配器
> class multiset;
std::map 核心知识点总结
一、基础概念与特性
- 容器类型
C++ STL 中的有序关联容器 ,存储键值对(key-value pairs) - 排序特性
元素始终按键(key)自动排序(默认升序) - 键唯一性
每个键在std::map中唯一(不允许重复键) - 底层实现
基于红黑树(自平衡二叉搜索树)实现,保证操作效率
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 默认分配器 | std::allocator<std::pair<const Key, T>> |
| 内存分配方式 | 动态分配(堆内存),每个节点独立分配 |
| 分配触发时机 | 插入新元素时为键值对分配内存;删除时释放对应内存 |
| 内存布局 | 树形结构存储,每个节点包含:父/子指针、颜色标志、键值对数据 |
| 连续内存 | ❌ 元素在内存中非连续存储,迭代器遍历可能产生缓存未命中 |
示例节点结构(简化):
cppstruct Node { Node* parent; Node* left; Node* right; bool color; // 红黑树颜色标志 std::pair<const Key, T> data; // 键值对 };
三、核心操作特性
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 插入 | O(log n) | insert() 或 emplace() 添加新元素 |
| 查找 | O(log n) | find()/count()/contains()(C++20) |
| 删除 | O(log n) | erase() 移除指定键或迭代器位置元素 |
| 访问 | O(log n) | operator[] 访问或创建元素;at() 边界检查访问 |
| 范围查询 | O(log n) | lower_bound()/upper_bound() 实现高效范围扫描 |
四、模板参数与自定义
cpp
template<
class Key, // 键类型(必须支持严格弱序比较)
class T, // 值类型
class Compare = std::less<Key>, // 比较器(默认升序)
class Allocator = std::allocator<std::pair<const Key, T>> // 内存分配器
> class map;
std::multimap 核心知识点总结
一、基础概念与特性
- 有序关联容器
存储可重复键值对(允许相同键对应多个值) - 红黑树实现
基于红黑树(自平衡二叉搜索树)实现 - 自动排序机制
元素始终按键升序排列 (默认std::less<Key>)
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 默认分配器 | std::allocator<std::pair<const Key, T>> |
| 节点结构 | 每个节点包含: - 键值对数据 - 父/子节点指针 - 红黑树颜色标志 |
| 内存分配 | insert() 操作时动态分配新节点 |
| 内存释放 | erase() 操作时立即释放节点内存 |
| 内存布局 | 树形结构存储,节点间非连续内存 |
节点结构示例:
cppstruct Node { Node* parent; // 父节点指针 Node* left; // 左子节点指针 Node* right; // 右子节点指针 bool color; // 红黑树颜色标志 std::pair<const Key, T> data; // 键值对 };
三、与 std::map 的关键区别
| 特性 | std::multimap |
std::map |
|---|---|---|
| 键唯一性 | ❌ 允许重复键 | ✅ 键必须唯一 |
| 插入行为 | 总是成功(不覆盖) | 键存在时插入失败或覆盖值 |
operator[] |
❌ 不支持 | ✅ 支持(自动创建键) |
| 查找返回值 | 返回匹配键的范围迭代器 | 返回单个元素迭代器 |
| 典型应用场景 | 一对多关系(如电话簿同名条目) | 键值唯一映射(如ID映射) |
四、核心操作特性
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 插入元素 | O(log n) | insert({key, value}) 可重复插入相同键值对 |
| 删除元素 | O(log n) | erase(key) 删除所有匹配键值;erase(iterator) 删除指定元素 |
| 键值查找 | O(log n) | find(key) 返回首个匹配键值的迭代器 |
| 范围查询 | O(log n) | equal_range(key) 获取相同键值的迭代器范围 |
| 元素计数 | O(log n) | count(key) 返回匹配键值的元素数量 |
五、特殊成员函数
- 键值范围访问
equal_range(key):获取相同键值的迭代器范围
auto [first, last] = phonebook.equal_range("Alice");
for (auto it = first; it != last; ++it)
std::cout << it->second; // 输出所有Alice的电话
std::unordered_set 核心知识点总结
一、基础概念与特性
- 无序关联容器
C++11 引入的哈希集合 ,存储唯一键值 (无重复元素)
相比unordered_map 仅存key 且不支持【】访问 - 哈希表实现
基于哈希表(链地址法或开放寻址法)实现 - 无序存储
元素存储顺序不固定,取决于哈希函数和桶分布
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 默认分配器 | std::allocator<Key> |
| 桶数组结构 | 维护动态数组存储桶指针(桶即链表头节点或开放寻址槽位) |
| 节点内存分配 | 插入时动态分配节点(含键值 + 链表指针) |
| 扩容机制 | 当负载因子(元素数/桶数)超过阈值(默认 1.0)时: 1. 桶数组翻倍扩容 2. 所有元素重新哈希到新桶 |
| 内存释放 | erase() 立即释放节点内存;桶数组在对象销毁时释放 |
典型节点结构(链地址法):
cppstruct Node { Key value; // 存储的元素值 Node* next; // 下一节点指针 };
三、核心操作特性
| 操作 | 平均复杂度 | 最坏复杂度 | 说明 |
|---|---|---|---|
| 插入元素 | O(1) | O(n) | insert(key) 或 emplace(args) |
| 删除元素 | O(1) | O(n) | erase(key) 或 erase(iterator) |
| 查找元素 | O(1) | O(n) | find(key)/contains(key)(C++20) |
| 迭代器稳定性 | ❌ 不稳定 | - | 扩容操作使所有迭代器失效 |
四、模板参数
cpp
template<
class Key, // 键类型
class Hash = std::hash<Key>, // 哈希函数对象
class KeyEqual = std::equal_to<Key>, // 键相等比较器
class Allocator = std::allocator<Key> // 分配器
> class unordered_set;
std::unordered_multiset 核心知识点总结
一、基础概念与特性
- 无序关联容器
存储可重复键值的集合,元素顺序由哈希函数决定 - 哈希表实现
基于链式哈希表实现(数组 + 链表冲突解决) - 快速查找特性
平均时间复杂度 O(1),最坏情况 O(n)
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 默认分配器 | std::allocator<Key> |
| 桶数组结构 | 动态数组存储桶指针(初始大小由实现定义) |
| 节点内存分配 | 每个元素独立分配节点(含键值 + 链表指针) |
| 动态扩容 | 当负载因子 (元素数/桶数) > max_load_factor()(默认1.0)时: - 桶数组扩容(通常翻倍) - 重新哈希所有元素 |
| 内存释放 | erase() 立即释放节点内存;桶数组在对象销毁时释放 |
节点结构:
cppstruct Node { Key value; // 存储的元素值 Node* next; // 下一节点指针 };
三、核心操作特性
| 操作 | 平均复杂度 | 最坏复杂度 | 说明 |
|---|---|---|---|
| 插入元素 | O(1) | O(n) | insert(key) 允许重复插入相同键值 |
| 删除元素 | O(1) | O(n) | erase(key) 删除所有匹配键值;erase(iterator) 删除指定元素 |
| 元素计数 | O(n) | O(n) | count(key) 返回匹配键值的元素数量 |
| 范围查询 | O(n) | O(n) | equal_range(key) 获取相同键值元素的范围迭代器对 |
四、模板参数
cpp
template<
class Key, // 键类型
class Hash = std::hash<Key>, // 哈希函数对象
class KeyEqual = std::equal_to<Key>, // 键相等比较器
class Allocator = std::allocator<Key> // 分配器
> class unordered_multiset;
std::unordered_map:哈希实现的键值对映射(键唯一)
哈希表核心知识点总结
一、基础结构
- 数组槽位
- 哈希表的第一维是数组结构,称为"槽"(slots)或"桶"(buckets)
- 每个槽存储键值对或冲突处理结构(链表/树的头节点)
二、容量机制
-
初始容量
- 创建时指定(如 Java
HashMap默认 16,Gomap默认 8) - 未指定时采用语言/库默认值
- 创建时指定(如 Java
-
动态扩容
- 触发条件:元素数量 >
当前容量 × 负载因子(通常 0.5-0.75) - 扩容策略:
- 倍增策略:容量翻倍(如 16 → 32),保持 2 的幂
- 质数策略:取大于 2 倍容量的最小质数
- 扩容后需重新哈希所有元素
- 触发条件:元素数量 >
三、内存分配机制
| 场景 | 内存分配行为 |
|---|---|
| 首次初始化 | ✅ 分配初始数组内存 |
| 触发扩容时 | ✅ 分配新数组内存 |
| 链表法插入新键 | ✅ 分配节点内存 |
| 开放寻址法插入新键 | ❌ 使用预分配槽位 |
| 更新已存在键的值 | ❌ 不分配新内存 |
四、冲突处理策略
-
链表法
- 每个槽位维护链表结构存储冲突元素
- 插入新键必分配节点内存
-
开放寻址法
- 所有元素直接存储在数组槽位中
- 通过线性探测/二次探测解决冲突
- 插入新键通常不分配额外内存
std::unordered_multimap 核心知识点总结
一、基础概念与特性
- 无序关联容器
C++11 引入的哈希键值对容器 ,允许重复键值(同键可对应多个值) - 哈希表实现
基于链式哈希表实现(数组 + 链表冲突解决) - 无序存储特性
元素顺序由哈希函数决定,遍历时无固定顺序
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 默认分配器 | std::allocator<std::pair<const Key, T>> |
| 桶数组结构 | 动态数组存储桶指针(初始大小由实现定义) |
| 节点内存分配 | 插入时动态分配节点(含键值对 + 链表指针) |
| 动态扩容 | 当负载因子 (元素数/桶数) > max_load_factor()(默认1.0)时: 1. 桶数组扩容(通常翻倍) 2. 所有元素重新哈希到新桶 |
| 内存释放 | erase() 立即释放节点内存;桶数组在对象销毁时释放 |
节点结构:
cppstruct Node { std::pair<const Key, T> data; // 键值对 Node* next; // 下一节点指针 };
三、核心操作特性
| 操作 | 平均复杂度 | 最坏复杂度 | 说明 |
|---|---|---|---|
| 插入元素 | O(1) | O(n) | insert({key, value}) 允许重复键值对插入 |
| 删除元素 | O(1) | O(n) | erase(key) 删除所有匹配键值;erase(iterator) 删除指定元素 |
| 键值查找 | O(1) | O(n) | find(key) 返回首个匹配键值的迭代器 |
| 范围查询 | O(1) | O(n) | equal_range(key) 获取相同键值的迭代器范围 |
| 迭代器稳定性 | ❌ 不稳定 | - | 扩容操作使所有迭代器失效 |
四、模板参数
cpp
template<
class Key, // 键类型
class T, // 值类型
class Hash = std::hash<Key>, // 哈希函数对象
class KeyEqual = std::equal_to<Key>, // 键相等比较器
class Allocator = std::allocator<std::pair<const Key, T>> // 分配器
> class unordered_multimap;
容器适配器(基于其他容器封装)
std::stack 核心知识点总结
一、基础概念与特性
- 容器适配器
C++ STL 中的栈结构容器适配器,提供后进先出(LIFO)操作接口 - 底层容器依赖
基于其他序列容器实现(默认使用std::deque) - 受限访问
仅允许在栈顶进行插入和删除操作
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 底层容器决定内存 | 内存管理完全由底层容器(如 std::deque)负责 |
| 默认底层容器 | std::deque(分段连续存储,动态扩容) |
| 内存分配行为 | 遵循底层容器的分配策略: - push() 可能触发扩容 - pop() 释放元素内存 |
| 无独立内存管理 | 作为适配器不直接管理内存,完全依赖底层容器实现 |
当使用默认
std::deque时:
- 内存分段存储在固定大小块中
- 动态扩容时分配新内存块
- 不释放已分配的内存块直到对象销毁
三、核心操作接口
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 入栈 | O(1) | push(value) 在栈顶插入元素 |
| 出栈 | O(1) | pop() 移除栈顶元素(不返回值) |
| 访问栈顶 | O(1) | top() 返回栈顶元素引用(空栈调用导致未定义行为) |
| 容量查询 | O(1) | size() 返回元素数量 empty() 判断是否为空 |
四、模板参数与自定义
cpp
template<
class T, // 元素类型
class Container = std::deque<T> // 底层容器类型
> class stack;
std::queue 核心知识点总结
一、基础概念与特性
- 容器适配器
C++ STL 中的队列结构容器适配器,提供先进先出(FIFO)操作接口 - 底层容器依赖
基于其他序列容器实现(默认使用std::deque) - 受限访问
仅允许在队尾插入元素,队头删除元素
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 底层容器决定内存 | 内存管理完全由底层容器(如 std::deque)负责 |
| 默认底层容器 | std::deque(分段连续存储,动态扩容) |
| 内存分配行为 | 遵循底层容器的分配策略: - push() 可能触发扩容 - pop() 释放元素内存 |
| 无独立内存管理 | 作为适配器不直接管理内存,完全依赖底层容器实现 |
当使用默认
std::deque时:
- 内存分段存储在固定大小块中
- 动态扩容时分配新内存块
- 不释放已分配的内存块直到对象销毁
三、核心操作接口
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 入队 | O(1) | push(value) 在队尾插入元素 |
| 出队 | O(1) | pop() 移除队头元素(不返回值) |
| 访问队头 | O(1) | front() 返回队头元素引用(空队列调用导致未定义行为) |
| 访问队尾 | O(1) | back() 返回队尾元素引用 |
| 容量查询 | O(1) | size() 返回元素数量 empty() 判断是否为空 |
四、模板参数与自定义
cpp
template<
class T, // 元素类型
class Container = std::deque<T> // 底层容器类型
> class queue;
std::priority_queue 核心知识点总结
一、基础概念与特性
- 容器适配器
C++ STL 中的优先级队列容器适配器,提供基于优先级的元素访问 - 堆结构实现
底层实现为二叉堆数据结构(默认最大堆) - 访问特性
- 仅能访问堆顶元素(优先级最高元素)
- 不支持随机访问或迭代器遍历
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 底层容器决定内存 | 内存管理由底层容器(默认 std::vector)负责 |
| 堆结构特性 | 元素以完全二叉树形式存储,满足堆序性质 |
| 内存分配行为 | 遵循底层容器的分配策略: - push() 可能触发扩容 - pop() 释放元素内存 |
| 默认容器 | std::vector(连续内存存储,支持高效随机访问) |
| 扩容机制 | 当底层 vector 容量不足时: 1. 分配新内存 2. 迁移元素并重建堆 |
内存布局示例(最大堆):
30 / \ 20 15 / \ 10 5 对应vector: [30, 20, 15, 10, 5]
三、核心操作接口
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 插入元素 | O(log n) | push(value) 插入元素并调整堆结构 |
| 删除堆顶 | O(log n) | pop() 移除堆顶元素并调整堆结构 |
| 访问堆顶 | O(1) | top() 返回堆顶元素引用(空队列调用导致未定义行为) |
| 容量查询 | O(1) | size() 返回元素数量 empty() 判断是否为空 |
四、模板参数与自定义
cpp
template<
class T, // 元素类型
class Container = std::vector<T>, // 底层容器
class Compare = std::less<typename Container::value_type> // 比较器
> class priority_queue;
std::bitset 核心知识点总结
一、基础概念与特性
- 固定大小位集合
C++ STL 提供的固定长度位数组容器,用于高效处理二进制标志位 - 编译时确定大小
大小N在编译时指定,无法运行时动态改变 - 内存高效存储
每个位仅占 1 bit 空间,无额外内存开销
二、内存管理机制
| 特性 | 说明 |
|---|---|
| 内存分配位置 | 栈内存(或作为成员变量时随对象分配) |
| 内存布局 | 连续内存块存储,按机器字长(word)分组 |
| 内存计算 | 总内存 = ceil(N / (sizeof(WordType) * CHAR_BIT)) * sizeof(WordType) |
| 无动态内存 | 不涉及堆内存分配,无析构释放操作 |
示例 :
std::bitset<64>在 64 位系统占用 8 字节(64/8=1 word)
std::bitset<65>在 64 位系统占用 16 字节(65/64≈2 words)
三、核心操作接口
| 操作 | 说明 |
|---|---|
| 位访问 | operator[] 访问特定位;test(pos) 带边界检查访问 |
| 位设置 | set(pos) 置位;reset(pos) 清零;flip(pos) 翻转 |
| 批量操作 | set() 全置位;reset() 全清零;flip() 全翻转 |
| 位运算 | 支持 &, ` |
| 转换操作 | to_ulong()/to_ullong() 转整数;to_string() 转二进制字符串 |
四、特殊功能
-
位统计
count()返回置位(1)的数量cppstd::bitset<8> bs(0b10101010); bs.count(); // 返回 4
`std::valarray
概述
std::valarray 是 C++ 标准库中的一个类模板,用于表示和操作数值数组,支持元素级数学运算和各种下标访问方式。它旨在优化数值计算,避免别名问题,并允许编译器进行循环融合等优化。
关键点
- 设计目的:专为高效数值数组操作设计,支持元素级运算、切片和间接访问,但不提供标准迭代器(如 vector)。
- 优化特性:操作可能返回代理对象以减少临时对象,支持并行化和循环优化,但实际实现中优化程度有限。
- 内存管理:元素连续存储在动态分配的数组中,默认构造函数不分配内存,其他构造函数根据大小分配;resize 可改变大小,可能导致重新分配。
- 限制:模板参数 T 需为数值类型(如算术类型或 std::complex);不支持自定义分配器。
- 争议与使用:虽标准但使用较少,常被 vector 或其他库取代;研究表明其性能优化在现代编译器中未充分实现,但适合简单数值任务。
基本用法
std::valarray 的实例化如 std::valarray<double> va(5);,创建大小为 5 的数组,所有元素默认初始化。支持如 va += 2.0; 的元素级运算,返回新 valarray 或修改原对象。
优势与注意事项
优势在于内置数学函数(如 sum、min)和运算符重载,便于数值代码编写。注意:resize 会使指针/引用失效;操作假设无别名以优化,但需小心使用。
std::valarray 详细说明
引言
std::valarray 是 C++ 标准库(头文件 <valarray>)中的类模板,用于表示数值数组并支持高效的元素级数学操作。它允许元素 wise 的算术运算、逻辑运算和各种下标操作,包括切片(slice)和间接访问(indirect)。 该类设计时考虑了无别名假设,类似于 C 语言的 restrict 关键字,从而允许编译器优化,如循环融合。 表达式如 v1 = a * v2 + v3; 可被优化为单次循环遍历。一些实现(如 GNU libstdc++ 和 LLVM libc++)内部使用表达式模板,但进一步优化较少见。 valarray 适合数值计算,但实际使用中常被 std::vector 或第三方库(如 Eigen)替代,因为其优化潜力在现代编译器中未完全实现。
valarray 的模板参数 T 必须满足 NumericType 要求,通常为算术类型、指针或类似 std::complex 的类。 它不支持标准容器接口(如迭代器),但 C++11 引入了 std::begin 和 std::end 的重载。
成员类型
- value_type:T,即存储元素的类型。
构造函数
std::valarray 提供多种构造函数,用于创建空数组或初始化数组:
- 默认构造函数 :
valarray(),创建空数组(大小 0),不分配内存。 - 大小指定 :
valarray(size_t count),分配 count 个元素,每个元素值初始化(默认构造)。 - 值初始化 :
valarray(const T& val, size_t count),分配 count 个元素,每个拷贝自 val。 - 数组拷贝 :
valarray(const T* ptr, size_t count),从 ptr 指向的数组拷贝 count 个元素。 - 初始化列表 (C++11):
valarray(initializer_list<T> ilist),从列表初始化,大小为列表长度。 - 拷贝/移动构造函数 :
valarray(const valarray&)和valarray(valarray&&),分配与源相同大小的存储,并拷贝/移动元素。
析构函数 ~valarray() 释放内部存储。
成员函数
成员函数包括赋值、访问、运算和聚合操作:
- 赋值 :
operator=,赋值内容,可能导致重新分配。 - 访问 :
operator[],返回元素引用、切片(slice_array)或掩码子数组(mask_array)。 - 一元运算符 :
operator+、operator-、operator~、operator!,对每个元素应用,返回新 valarray。 - 复合赋值 :
operator+=等,对每个元素应用,返回 *this。 - 交换 :
swap,常数时间交换内容,不失效引用。 - 大小 :
size,返回元素数。 - 调整大小 :
resize(size_t new_size)或resize(size_t new_size, const T& val),改变大小;若增大,新增元素默认/值初始化;若缩小,销毁多余元素;失效指针/引用。 - 聚合 :
sum、min、max,计算总和、最小/最大值。 - 移位 :
shift(零填充移位)、cshift(循环移位)。 - 应用函数 :
apply,对每个元素应用指定函数,返回新 valarray。
非成员函数
- 交换 (C++11):
std::swap(std::valarray)。 - 迭代器 (C++11):
std::begin、std::end,返回指向开始/结束的指针。 - 二元运算符 :
operator+等,元素级应用,返回新 valarray。 - 比较运算符 :
operator==等,元素级比较,返回 bool valarray。 - 数学函数 :
abs、exp、log、pow、sqrt、sin、cos等,元素级应用,返回新 valarray。
运算符
- 一元:成员函数形式,对元素应用。
- 复合赋值:成员函数,修改自身。
- 二元:非成员,元素级运算,支持 valarray 与 valarray 或 scalar。
- 比较:非成员,返回 bool valarray。
内存分配与管理
std::valarray 的元素存储在连续的动态分配数组中,类似于 std::vector 但无完整迭代器支持。 默认构造函数不分配内存。 其他构造函数根据指定大小在堆上分配连续块,并初始化元素。 resize 操作可能导致重新分配:若新大小大于当前,分配更多空间并初始化新增元素;若小于,销毁多余元素并可能释放内存。 实现可能使用 copy-on-write 或 copy-on-reference 优化以减少拷贝。 无自定义分配器支持;resize 或赋值失效所有指针/引用。 一些实现(如 Microsoft)提供非标准 free() 以释放存储。
辅助类与高级特性
- 切片与子数组 :使用
std::slice、std::gslice、slice_array、gslice_array、mask_array、indirect_array支持子集操作。 - 模板参数推导(C++17):支持从初始化列表等推导 T。
- 并行化潜力:设计允许操作并行执行,但依赖实现。
示例
cpp
#include <valarray>
#include <iostream>
int main() {
std::valarray<int> va = {1, 2, 3, 4};
va += 5; // 元素级加法: {6,7,8,9}
std::cout << va.sum() << std::endl; // 输出 30
va.resize(2); // 变为 {6,7}
return 0;
}
此示例展示基本运算和 resize。
表格:常见成员函数总结
| 函数 | 描述 | 返回类型 | 注意事项 |
|---|---|---|---|
| size | 返回元素数 | size_t | 常量时间 |
| resize | 改变大小 | void | 可能失效引用 |
| sum | 元素总和 | T | 假设 T 支持 + |
| min/max | 最小/最大 | T | 假设 T 支持 < |
| apply | 应用函数 | valarray | 返回新数组 |
| shift/cshift | 移位 | valarray | shift 零填充,cshift 循环 |
| swap | 交换 | void | 常数时间,不失效引用 |
表格:运算符支持
| 类型 | 示例 | 行为 |
|---|---|---|
| 一元 | +va, -va | 新 valarray,元素应用 |
| 二元 | va1 + va2 | 新 valarray,元素级 |
| 复合 | va += scalar | 修改 va |
| 比较 | va1 == va2 | bool valarray,元素级 |
| 数学 | std::sin(va) | 新 valarray,元素应用 |