
直接说结论:std::deque 是 C++ 标准库中支持高效两端插入/删除的序列容器,比 std::vector 多出 push_front() 和 pop_front(),但随机访问性能略弱于 vector(常数因子稍大,仍为 O(1))。
如何声明和初始化 deque
必须包含头文件 ,且所有操作都依赖模板参数类型。常见误写是漏掉命名空间或用错尖括号语法。
- 空容器:
std::dequedq; - 指定大小并初始化为 0:
std::deque→ 含 5 个dq(5); 0 - 指定大小并初始化为某值:
std::deque→ 含 5 个dq(5, 42); 42 - 从数组构造:
int arr[] = {1, 2, 3}; std::dequedq(arr, arr + 3); - C++11 起支持初始化列表:
std::deque<:string> dq = {"a", "b", "c"};
两端插入与删除的正确写法
deque 的核心价值就在前后操作都是 O(1) 均摊复杂度,但要注意:没有 insert_front() 这种函数,只有 push_front() 和 pop_front();pop_front() 不返回值,取值需先用 front()。
-
前端插入:
dq.push_front(10); -
后端插入:
dq.push_back(20); - 前端删除:
dq.pop_front();(不返回元素,删前请先if (!dq.empty()) x = dq.front();) - 后端删除:
dq.pop_back(); - 获取首尾元素(不删除):
dq.front()、dq.back()—— 若容器为空,行为未定义(不是抛异常,是崩溃或脏读)
std::dequedq = {1, 2, 3}; dq.push_front(0); // dq → {0,1,2,3} dq.push_back(4); // dq → {0,1,2,3,4} dq.pop_front(); // dq → {1,2,3,4} dq.pop_back(); // dq → {1,2,3}
迭代器与随机访问注意事项
deque 支持随机访问(dq[i]、dq.at(i)),也支持所有标准迭代器操作,但它的内存不连续 —— 实际由多个固定大小缓冲区组成。这导致两个隐性影响:
立即学习“C++免费学习笔记(深入)”;
-
&dq[0] + i != &dq[i]:指针算术不成立,不能把dq.data()当作 C 数组传给需要连续内存的 API(vector可以,deque不行) - 迭代器失效规则比
vector宽松:仅在对应端插入/删除时,另一端的迭代器仍有效;但中间插入(insert(pos, ...))会导致所有迭代器失效 -
at()会做边界检查并抛std::out_of_range,operator[]不检查 —— 和vector行为一致
什么时候该用 deque 而不是 vector 或 list
选 deque 不是因为“它两头快”,而是因为你的场景同时满足:需要频繁在两端增删 + 需要较快的随机访问 + 不要求内存连续。
- ✅ 推荐用:
滑动窗口最大值、实现栈+队列混合结构、日志缓冲区(头进尾出或尾进头出) - ❌ 别硬套:
需要传给 OpenGL 的顶点数组(要vector::data())、99% 时间只在尾部操作(用vector更缓存友好)、频繁在中间插入/删除(改用list或forward_list) - ⚠️ 注意:
deque构造/析构单个元素的开销略高于vector(因涉及缓冲区管理),元素类型很重时(如含大数组的 struct)要实测
最容易被忽略的一点:deque 的 size() 是 O(1),但某些老编译器(如早期 MSVC)实现曾是 O(n),现在主流 STL(libstdc++、libc++、MSVC STL)均已保证 O(1)。不过,如果你在嵌入式环境或自研 STL 上使用,务必查证文档。










