C++ STL库_双端队列dqueue

STL之双向队列 deque 双端队列(dequeue) 采用线性表顺序存储结构,且支持随机访问,即可以直接用下标来访问元素,顾名思义其是双向开口,可以快速在首尾插入、删除数据。 其头文件是<deque>,主要包含函数: push_back():在队尾压入元素 push_front():在队头压入元素 pop_back():删除最后一个元素 pop_front():删除第一个元素 front():返回第... 阅读详情

一、std::deque的核心性质

deque(Double-Ended Queue)是 STL 中兼顾 “随机访问” 和 “双端高效操作” 的动态容器,核心特性如下:

  1. 双端操作高效:队首 / 队尾的插入、删除操作均为O(1)时间复杂度(平均);
  2. 随机访问支持:可以像vector一样通过下标[]或at()访问元素,时间复杂度O(1);
  3. 分段连续内存:底层不是单一连续内存块,而是 “分段连续 + 中控器管理” 的结构,避免了vector整体扩容的内存拷贝开销;
  4. 动态扩容:首尾均可扩展,扩容时仅需新增缓冲区(无需移动已有元素),扩容成本远低于vector;
  5. 迭代器特性:提供随机访问迭代器(和vector一致),但迭代器内部会记录缓冲区信息,比vector迭代器稍复杂;
  6. 无内存浪费:相比vector的 “预分配多余空间”,deque的缓冲区大小固定,内存利用率更高(但中控器会占用少量额外内存);
  7. 中间操作低效:中间位置的插入 / 删除仍需移动元素(或跨缓冲区调整),时间复杂度O(n)(和vector类似,比list差)。

二、deque的底层存储结构(核心难点)

deque的底层结构是vector和list的 “折中设计”,理解它能解释其所有特性,结构分为两部分:

1. 核心结构(可视化)

2. 各部分详解
组件本质作用
中控器(Map)动态数组(存储T*类型指针)管理所有缓冲区的地址,相当于 “索引表”,中控器自身扩容时仅拷贝指针(成本极低);
缓冲区(Buffer)固定大小的连续内存块(存储实际元素)每个缓冲区存储相同数量的元素(通常默认 512 字节,可通过编译器调整),元素在缓冲区内连续存储;
3. 关键操作的底层逻辑
  • 随机访问(deque[i]):

    1. 计算i属于哪个缓冲区(i / 缓冲区大小)→ 找到中控器中对应的指针;
    2. 计算i在缓冲区中的偏移(i % 缓冲区大小)→ 定位到具体元素;
    3. 全程O(1),仅多两次算术运算,和vector几乎无性能差异。
  • 队首插入(push_front):

    1. 若头部缓冲区有空闲空间,直接在头部插入;
    2. 若头部无空间,新增一个缓冲区,将其指针加入中控器头部,再插入元素;
    3. 无需移动已有元素,O(1)复杂度。
  • 扩容(对比vector):

    • vector:扩容时需分配新的更大连续内存,拷贝所有元素,释放旧内存(O(n)成本);
    • deque:扩容时仅需新增缓冲区,中控器若满则扩容(仅拷贝指针),已有元素无需移动(O(1)成本)。

三、std::deque的常用接口(分类详解)

使用deque需包含头文件:#include <deque>,以下是最常用的接口,按功能分类讲解。

1. 构造函数
构造方式说明
deque<T> d;默认构造,空双端队列
deque<T> d(n);构造包含n个默认构造元素的队列
deque<T> d(n, val);构造包含n个值为val的元素的队列
deque<T> d(d2);拷贝构造,复制d2的所有元素
deque<T> d(begin, end);范围构造,复制[begin, end)区间内的元素(支持数组 / 其他容器迭代器)
deque<T> d(std::move(d2));移动构造,接管d2的资源(C++11+)
2. 元素访问(支持随机访问)
接口说明
d[i]访问第i个元素(无越界检查,越界会导致未定义行为)
d.at(i)访问第i个元素(带越界检查,越界抛出out_of_range异常)
d.front()返回队首元素的引用(可修改)
d.back()返回队尾元素的引用(可修改)
d.data()返回指向第一个缓冲区的指针(C++17+,极少用)
3. 容量相关
接口说明
d.empty()判断队列是否为空,返回bool
d.size()返回元素个数,类型size_t
d.max_size()返回理论最大可存储元素数(受内存限制)
d.resize(n)调整队列大小为n:若n>size(),新增默认构造元素;若n<size(),删除尾部元素
d.resize(n, val)调整大小为n,新增元素值为val
d.shrink_to_fit()释放未使用的缓冲区内存(C++11+,仅为建议,编译器可忽略)
4. 修改操作(核心,双端特性体现)
接口说明
d.push_front(val)队首插入元素val(拷贝 / 移动构造)
d.push_back(val)队尾插入元素val(拷贝 / 移动构造)
d.emplace_front(args...)队首直接构造元素(无需先创建对象,更高效,C++11+)
d.emplace_back(args...)队尾直接构造元素(C++11+)
d.pop_front()删除队首元素(无返回值)
d.pop_back()删除队尾元素(无返回值)
d.insert(pos, val)在迭代器pos位置插入val,返回新元素的迭代器
d.insert(pos, n, val)在pos位置插入n个val
d.insert(pos, begin, end)在pos位置插入[begin, end)区间的元素
d.erase(pos)删除pos位置的元素,返回下一个元素的迭代器
d.erase(begin, end)删除[begin, end)区间的元素,返回下一个元素的迭代器
d.swap(d2)交换两个deque的内容(中控器 + 缓冲区指针,成本极低)
d.clear()清空所有元素(释放缓冲区内存,中控器保留)
5. 迭代器(支持随机访问)
接口说明
d.begin()返回指向第一个元素的普通迭代器
d.end()返回指向最后一个元素下一位的普通迭代器
d.cbegin()返回指向第一个元素的常量迭代器(只读,C++11+)
d.cend()返回指向最后一个元素下一位的常量迭代器(只读)
d.rbegin()返回指向最后一个元素的反向迭代器
d.rend()返回指向第一个元素前一位的反向迭代器

四、std::deque完整使用示例

以下代码覆盖deque的核心接口,可直接编译运行:

#include <iostream>
#include <deque>
#include <string>
using namespace std;

// 自定义结构体,演示emplace系列接口
struct Student {
    string name;
    int score;
    // 构造函数
    Student(string n, int s) : name(n), score(s) {}
};

int main() {
    // ========== 1. 构造deque ==========
    deque<int> d1; // 默认构造
    deque<int> d2(3, 10); // 3个10:[10,10,10]
    int arr[] = {1,2,3,4};
    deque<int> d3(arr, arr+4); // 范围构造:[1,2,3,4]

    // ========== 2. 元素访问 ==========
    cout << "d3[1] = " << d3[1] << endl; // 2(无越界检查)
    cout << "d3.at(2) = " << d3.at(2) << endl; // 3(带越界检查)
    cout << "d3队首:" << d3.front() << endl; // 1
    cout << "d3队尾:" << d3.back() << endl; // 4

    // 修改元素
    d3[3] = 40;
    cout << "修改后d3队尾:" << d3.back() << endl; // 40

    // ========== 3. 双端插入/删除 ==========
    d1.push_front(5); // 队首插入5:[5]
    d1.push_back(6);  // 队尾插入6:[5,6]
    d1.emplace_front(4); // 队首直接构造4:[4,5,6]
    d1.emplace_back(7);  // 队尾直接构造7:[4,5,6,7]

    cout << "d1插入后大小:" << d1.size() << endl; // 4

    d1.pop_front(); // 删除队首:[5,6,7]
    d1.pop_back();  // 删除队尾:[5,6]
    cout << "d1删除后:" << d1[0] << "," << d1[1] << endl; // 5,6

    // ========== 4. 中间插入/删除 ==========
    // 获取指向第二个元素的迭代器
    auto it = d3.begin() + 1;
    d3.insert(it, 99); // 在位置1插入99:[1,99,2,3,40]
    cout << "插入99后d3:";
    for (int num : d3) cout << num << " "; // 1 99 2 3 40
    cout << endl;

    d3.erase(d3.begin() + 1); // 删除位置1的99:[1,2,3,40]
    cout << "删除99后d3:";
    for (int num : d3) cout << num << " "; // 1 2 3 40
    cout << endl;

    // ========== 5. 自定义类型示例 ==========
    deque<Student> d_stu;
    // emplace_back直接传构造参数,无需先创建Student对象
    d_stu.emplace_back("小明", 95);
    d_stu.emplace_front("小红", 98);
    cout << "第一个学生:" << d_stu.front().name << ",分数:" << d_stu.front().score << endl; // 小红 98

    return 0;
}

运行结果:

d3[1] = 2
d3.at(2) = 3
d3队首:1
d3队尾:4
修改后d3队尾:40
d1插入后大小:4
d1删除后:5,6
插入99后d3:1 99 2 3 40 
删除99后d3:1 2 3 40 
第一个学生:小红,分数:98

五、deque vs vector vs list(核心对比)

特性dequevectorlist
随机访问支持(O(1))支持(O(1),更高效)不支持(O(n))
队首插入 / 删除O(1)(高效)O(n)(需移动元素)O(1)(高效)
队尾插入 / 删除O(1)(高效)O(1)(平均,扩容时O(n))O(1)(高效)
中间插入 / 删除O(n)(需移动元素)O(n)(需移动元素)O(1)(仅调整指针)
内存连续性分段连续完全连续不连续(节点 + 指针)
扩容成本极低(仅新增缓冲区)高(整体拷贝元素)无扩容成本(节点动态分配)
内存利用率较高(固定缓冲区)较低(预分配多余空间)低(额外指针开销)
迭代器稳定性插入 / 删除首尾时稳定,中间操作可能失效扩容时迭代器全部失效,中间操作局部失效所有操作迭代器均稳定(除被删除节点)
使用场景建议
  • 选deque:需要随机访问 + 双端高效操作(如实现队列 / 栈、滑动窗口);
  • 选vector:需要极致的随机访问性能 + 仅队尾操作(如存储大量数据、数值计算);
  • 选list:需要大量中间插入 / 删除 + 迭代器稳定性(如频繁修改的链表结构)。

总结

  1. std::deque是分段连续的双端队列,兼顾vector的随机访问和list的双端高效操作,扩容成本极低;
  2. 核心接口支持双端插入(push_front/push_back)、双端删除(pop_front/pop_back)和随机访问([]/at());
  3. 使用场景:优先用于需要 “首尾操作 + 随机访问” 的场景(如队列 / 栈的底层实现、滑动窗口算法),避免用于大量中间插入 / 删除的场景。
C++实现双端队列(数组模拟)【每一步详细深入讲解,代码清晰、简单、易懂】 如左图,左指针已经到了左边界,但队列还没满按理说应该可以左入队,再次入队之后左指针应该到达最右边,这样才能实现继续入队,现在只要实现左指针到达左边界时再入队,指针移动到最右边的操作。经过思考,发现一个小于B的数A模B依然等于A,而如果A等于B,那A模B就等于0,-1+B模B等于B-1,而A加上任意个B 再模B依然等于A。但是,这样怎么看怎么别扭,左边和右边都执行了入队,但左指针位置无元素,右指针位置却有,而且左右入队操作不同,不太符合通用原则。发现,左边入队是正常,但,右边入队时入队的值覆盖了之前的值! 阅读详情

相关推荐

C++ STL常见用法

文章目录C++_STL容器stringvectorstackqueuedqueue(双端队列)queue(队列)priority_queuelist(双向链表)自定义链表-struct结构mapunordered_map树图算法重载运算符算法思想--递归 C++_STL 容器 包括string类,顺序容器,容器适配器,关联容器 string 创建与初始化 string a="adwdad"; string a[4] = {"twenty", "thirty", "forty", "fifty"};

Daily Code. 517

deque(双端队列)介绍

双端队列介绍

行码棋 2万+

【STL模板】双端队列

【STL 模板】双端队列

weixin_42596089的博客 967

「数据结构详解·十」双端队列 & 单调队列的初步

双端队列详解 & 单调队列的初步详解

Leo_Chenjy的博客 715

Ansys Zemax实战:5步搞定衍射光学元件(DOE)设计,附赠超透镜(metalens)避坑指南

本文详细介绍了使用Ansys Zemax进行衍射光学元件(DOE)和超透镜(metalens)设计的5步实战流程。从基础光学系统搭建到相位面设计验证,再到制造准备与实测对比,全面解析了OpticStudio中的关键技巧和常见避坑指南,帮助工程师高效完成复杂光学元件设计。

orange的博客 617

Python+AI能源管理实战:从电力负荷预测到智能调度的全流程开发

本系统展示了Python在能源管理领域的强大能力,通过AI技术实现了从预测到优化的智能决策闭环。随着碳中和目标的推进,智能能源系统将成为新型电力系统的核心大脑。📌 专业建议:系统部署需考虑网络安全防护,关键控制指令应设置多重验证机制!关注我的优快云账号获取能源系统安全最佳实践~下期预告:我们将探索Python在智慧医疗中的应用,开发基于多模态数据的智能诊断辅助系统。想提前获取代码?评论区留言"智慧医疗"获取GitHub源码链接!

资深全栈架构师,乐于在 优快云 分享技术见解,与大家携手共进,共攀技术巅峰! 623

【C++】STL常用容器总结之五:双端队列deque

所谓的deque是”double ended queue”的缩写,双端队列不论在尾部或头部插入元素,都十分迅速。而在中间插入元素则会比较费时,因为必须移动中间其他的元素。双端队列是一种随机访问的数据类型,提供了在序列两端快速插入和删除操作的功能,它可以在需要的时候改变自身大小,完成了标准的C++数据结构中队列的所有功能。 Vector是单向开口的连续线性空间,deque则是一种双向开口的连续线性空

长相忆兮长相忆的专栏 1万+

从零构建:如何在VSCode中为HBuilderX迁移的UniApp项目搭建TypeScript支持环境

本文详细指导如何将HBuilderX中的UniApp项目迁移至VSCode并搭建TypeScript支持环境。通过pnpm包管理器初始化项目、配置tsconfig.json和vite.config.ts文件,实现工程化迁移与TypeScript深度集成,提升开发效率和代码质量。

book8的博客 1050

【C++】deque双端队列

STL容器:deque

weixin_63449996的博客 2740

从零到一:ESP32-P4 PPA加速的配置陷阱与避坑指南

本文详细解析ESP32-P4结合LVGL的PPA硬件加速配置中的常见陷阱,包括内存对齐、缓冲区设置和同步机制等关键问题。提供实用的避坑指南和优化方案,帮助开发者高效启用esp32p4的PPA加速功能,显著提升图形渲染性能。

sky77的博客 395

七天征服AutoSAR/SomeIP_01速成配置并代码生成

本文为AutoSAR中SomeIP配置开发的实操指南摘要,重点介绍通过通信矩阵快速构建SomeIP工程的方法。核心内容包括:1)基于Excel通信矩阵生成系统描述文件(arxml);2)在AutoSAR工具中导入文件自动生成协议栈配置,涵盖ETHIF、SoAd等模块;3)关键报错处理(COM/PDUR/SOAD/SD模块的配置修正);4)SomeIPXF的数据编解码配置;5)SWC组件与RTE任务映射。教程强调"先完成再完美"的实践原则,指导开发者快速生成基础代码框架,为后续协议调试奠定

大叔带刺的博客 302

C++ STL deque(双端队列)学习笔记:容器界的 “全能选手”

本文介绍了C++中的双端队列(deque)容器,通过生动比喻和代码示例全面讲解了其功能特性。主要内容包括:1. deque的5种构造方法,从空容器到带初始值的批量创建;2. 灵活的插入删除操作,支持两端高效增删和中间位置操作;3. 多种元素访问方式,包括随机访问和安全访问;4. 大小管理和内容交换等实用功能;5. 通过VIP排队系统的实际案例展示典型应用场景;6. 与vector、queue的对比分析,帮助选择合适的容器。文章采用通俗易懂的语言风格,配合丰富注释的代码示例,既适合初学者理解基础概念,也能帮助

qq_63683271的博客 868

基于STM32设计的环境监测系统(华为云IOT)_300

随着空气污染问题日益严峻,环境空气质量的监测变得愈加重要。为了解决这一问题,本项目设计并实现了一款基于STM32的空气质量监测设备,能够实时监测空气中的温湿度、二氧化碳浓度和甲醛浓度,并通过OLED显示屏展示数据。此外,设备支持通过WIFI模块将数据上传至云端,用户可以通过手机APP或Windows上位机查看实时数据。设备采用MQTT协议与华为云IOT物联网服务器进行数据通信,确保数据的实时性和可靠性。本项目还结合了低功耗设计和高灵敏度传感器,使得设备能够高效稳定地运行,并实现远程监控功能。

695

C++---deque双端队列

deque deque双端队列,是C++,STL标准模板库中提供的一种容器。 什么是双队列 队列:是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。 故名思意:双端队列就是,在队列的前端与后端都可以进行插入删除操作。 双端队列的底层结构 底层为每个结点都申请了一份空间。 双端队列底层是一个假象的连续空间,实际上是分段存储的,我们平...

qq_42708024的博客 429

学习笔记:TF卡启动荔枝派Nano(全志F1C200S)

荔枝派Nano编译Kernel报错报错内容如下编译烧录 报错内容如下 No controllers found No ethernet found. 从这些报错我真没看从出啥问题,也是在网上找,说是没有找到flash,是因为淘宝买的板子更换了flash,需要在u-boot里面重新适配型号: 板子的型号为xt25f128,但是实际u-boot的配置里面不是需要重新更改: u-boot/arch/arm/dts/suniv-f1c100s-licheepi-nano.dts &spi0 { pin

热爱科技,物联,程序开发等 2133

基于DFT的滤波系列:加窗滤波的 Matlab 实现

在实际应用中,你可以尝试不同类型的窗函数(如汉宁窗、汉明窗等)以及不同的滤波参数来获得所需的滤波效果。此外,还可以进一步了解 DFT 和窗函数的原理,以及其他数字信号处理技术的应用。加窗滤波是一种常用的数字信号处理技术,它通过在频域上应用窗函数来改善信号的频谱特性。我们通过定义输入信号、应用窗函数、进行 DFT 和逆 DFT,实现了滤波过程,并通过绘图进行了可视化。在频域上进行加窗滤波的关键是将窗函数应用于 DFT 的结果。首先,我们需要定义一个输入信号,这里我们使用一个简单的正弦波作为示例。

m0_47037246的博客 462

C++ 容器 deque(双端队列)

deque的结构讲解,函数讲解,自我实现

2301_80772499的博客 1025

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

【十八】【C++】deque双端队列简单使用和deque底层实现探究(部分代码)

struct __deque_iterator {//deque迭代器定义了一个模板,T是数据类型,Ref是引用类型,Ptr是指针类型,BufSiz是缓冲区大小。定义了一个结构体,作为deque的迭代器。//结点的大小//结点指针定义了迭代器和常量迭代器类型,分别用于修改和访问deque元素。定义了一个静态成员函数,用来计算每个缓冲区的大小。定义了为。这表示是一个随机访问迭代器,支持像数组一样的快速随机访问。

m0_74163972的博客 1616

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

【STL】| C++ 栈和队列(详解、deque(双端队列)介绍、容器适配器的初步引入)

今天我们要讲解的结构是栈和队列这两个的具体实现相比于前面我们学的string、vector、list都要简单得多(因为容器适配器的引入)如果有需要了解这两个数据结构的具体函数用法的话,也可以在较为官方的网站上进行查阅,如下kw=stack栈符合的原理是后进先出,图示如下:栈最常用的就是入栈、出栈,如果要将全部数据取出来的话,就写一个while循环判断栈是否为空(empty),然后挨个取 top(),出栈s1.push(1);s1.push(2);s1.push(3);s1.push(4)

2302_80023639的博客 990

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

C++双端队列deque源码的深度学习(stack,queue的默认底层容器)

deque是C++标准模板库(STL)中的一个容器,代表“双端队列”(double-ended queue)。deque支持在其前端(front)和后端(back)进行快速插入和删除操作,并且它在序列的中间插入和删除元素时通常比vector或list更高效。

weixin_72492465的博客 2354

Deque( Double-Ended Queue,双端队列)

(全称,双端队列)是一种允许在(队头和队尾)同时进行插入和删除操作的线性数据结构。如果说普通的队列(Queue)是“排队买票”,那么 Deque 就像是一个两头都能进出的神奇隧道。

m0_46322965的博客 947

C++STL deque

deque:双端队列容器底层数据结构:动态开辟的二维数组,一维数组从2开始,以2倍的方式进行扩容,每次扩容后,原来第二维的数组,从新的第一维数组的下标oldsize/2开始存放,上下都预留相同的空行,方便支持deque的首尾元素添加。第一维空间大小是MAP_SZIE=2,第二维和元素类型有关。如果T是int类型,则第二维空间大小是4096/4=1024个。双端队列,两个端可以做队头,或者队尾。相当于2个方向都有2个角色。

ljy的博客 349

C++ STL 基础

文章目录C++ STL 基础vector初始化常用成员函数deque初始化成员函数list初始化成员函数其他set C++ STL 基础 STL: Standard Template Library; STL的常规操作:查询,插入,删除,修改; 在C++中使用标准模板库提供的容器,需要加入相应的头文件,并且使用命名空间std; 容器适配器头文件:queue; stack; 容器头文件:vecto...

LiCM_CU的博客 837

C++STL之deque

deque 双端队列 deque和vector类似,可以用索引来取值,但是它在内存中的存储不是连续的,所以 addr=&deque,addr++这种操作可能会产生灾难性的后果,但是,迭代器可以进行这种操作。 与vector不同的是,deque可以双端插入(删除),多了push_front() and pop_front() 初始化 deque 名称(n,value) 成员函数与之前和大...

qq_37724465的博客 180

C++STL之stack,queue与容器适配器

什么是容器适配器?适配器是一种设计模式,它就像一个转换头,能将一个类的接口转换成用户所希望的另一种接口。STL中的stack、queue和priority_queue都是容器适配器,它们没有自己独立的数据结构,而是“适配”了其他容器(如deque, vector)的接口,提供了新的、特定的行为。容器适配器通过封装和限制接口,将通用的顺序容器转化为具有特定语义的专用数据结构。首先在代码清晰度方面,使用 stack 比直接用 vector 并约定只能操作尾部更能明确表达程序员的意图;

2301_79969685的博客 1002

【C++之deque和priority_queue的应用】

C++学习笔记015 -- deque和priority_queue的剖析与模拟实现等知识

m0_69455439的博客 610
上一篇: C++ STL库_队列queue
下一篇: Linux进程组 会话
Howrun777
博客等级 码龄1年 133粉丝 100原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值