C++双端队列知识点+习题

在C++中,双端队列(Deque,发音为“deck”)是标准模板库(STL)中的一种容器适配器,其全称为Double-Ended Queue。它结合了队列和栈的特点,允许在容器的两端(前端和后端)进行高效的插入和删除操作。
std::deque是C++ STL中实现双端队列的具体类模板,它提供了丰富的成员函数和操作接口,使其在多种场景下都非常有用。
一、 C++双端队列知识点
1. std::deque的基本特性
两端操作:可以在容器的前端(
front)和后端(back)进行插入、删除和访问操作。随机访问:支持通过索引访问元素,类似于数组或
std::vector。动态扩展:与
std::vector类似,std::deque可以根据需要动态扩展内存,但它的扩展机制更复杂,因为它需要同时管理两端的内存。内存管理:
std::deque内部通常使用多个固定大小的内存块(称为“缓冲区”)来存储元素。这种设计使得两端操作的效率很高,但随机访问的效率略低于std::vector。
2. std::deque的构造和初始化
std::deque可以通过多种方式构造:
默认构造:创建一个空的双端队列。
指定大小和默认值:创建一个具有指定大小的双端队列,并用默认值填充。
初始化列表:使用初始化列表直接构造双端队列。
从另一个容器复制或移动构造。
#include <deque>
#include <iostream>int main() {// 默认构造std::deque<int> dq1;// 指定大小和默认值std::deque<int> dq2(5, 10); // 5个元素,每个值为10// 初始化列表std::deque<int> dq3 = {1, 2, 3, 4, 5};// 从另一个容器复制构造std::deque<int> dq4(dq3);std::cout << "dq1 size: " << dq1.size() << std::endl;std::cout << "dq2: ";for (int x : dq2) {std::cout << x << " ";}std::cout << "\ndq3: ";for (int x : dq3) {std::cout << x << " ";}std::cout << "\ndq4: ";for (int x : dq4) {std::cout << x << " ";}std::cout << std::endl;return 0;
}
3. 常用操作
3.1 插入操作
前端插入:
push_front(),在容器前端插入一个元素。后端插入:
push_back(),在容器后端插入一个元素。指定位置插入:
insert(),可以在任意位置插入一个或多个元素。
#include <deque>
#include <iostream>int main() {std::deque<int> dq = {1, 2, 3};// 前端插入dq.push_front(0);// 后端插入dq.push_back(4);std::cout << "Deque after insertions: ";for (int x : dq) {std::cout << x << " ";}std::cout << std::endl;// 指定位置插入auto it = dq.begin() + 2; // 指向索引2的位置dq.insert(it, 10); // 在索引2的位置插入10std::cout << "Deque after insertion at position: ";for (int x : dq) {std::cout << x << " ";}std::cout << std::endl;return 0;
}
3.2 删除操作
前端删除:
pop_front(),删除容器前端的元素。后端删除:
pop_back(),删除容器后端的元素。指定位置删除:
erase(),删除任意位置的元素。
#include <deque>
#include <iostream>int main() {std::deque<int> dq = {0, 1, 10, 2, 3, 4};// 前端删除dq.pop_front();// 后端删除dq.pop_back();std::cout << "Deque after deletions: ";for (int x : dq) {std::cout << x << " ";}std::cout << std::endl;// 指定位置删除auto it = dq.begin() + 2; // 指向索引2的位置dq.erase(it); // 删除索引2的元素std::cout << "Deque after erasing at position: ";for (int x : dq) {std::cout << x << " ";}std::cout << std::endl;return 0;
}
3.3 访问操作
访问前端元素:
front(),返回前端元素的引用。访问后端元素:
back(),返回后端元素的引用。通过索引访问:
operator[]或at(),支持随机访问。
#include <deque>
#include <iostream>int main() {std::deque<int> dq = {0, 1, 2, 3, 4};std::cout << "Front element: " << dq.front() << std::endl;std::cout << "Back element: " << dq.back() << std::endl;// 通过索引访问std::cout << "Element at index 2: " << dq[2] << std::endl;std::cout << "Element at index 3 (using at()): " << dq.at(3) << std::endl;return 0;
}
3.4 其他操作
清空容器:
clear(),删除所有元素。检查是否为空:
empty(),判断容器是否为空。获取大小:
size(),返回容器中元素的数量。交换内容:
swap(),与另一个std::deque交换内容。
#include <deque>
#include <iostream>int main() {std::deque<int> dq = {0, 1, 2, 3, 4};std::cout << "Is deque empty? " << (dq.empty() ? "Yes" : "No") << std::endl;std::cout << "Size of deque: " << dq.size() << std::endl;// 清空容器dq.clear();std::cout << "Deque size after clear: " << dq.size() << std::endl;// 交换内容std::deque<int> dq2 = {10, 20, 30};dq.swap(dq2);std::cout << "Deque after swap: ";for (int x : dq) {std::cout << x << " ";}std::cout << std::endl;return 0;
}
4. 迭代器支持
std::deque支持双向迭代器,可以使用begin()、end()、rbegin()和rend()等方法获取迭代器,并通过迭代器进行遍历、插入和删除操作。
#include <deque>
#include <iostream>int main() {std::deque<int> dq = {0, 1, 2, 3, 4};// 使用迭代器遍历for (auto it = dq.begin(); it != dq.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;// 使用范围for循环for (int x : dq) {std::cout << x << " ";}std::cout << std::endl;// 使用反向迭代器for (auto it = dq.rbegin(); it != dq.rend(); ++it) {std::cout << *it << " ";}std::cout << std::endl;return 0;
}
5. 内存管理
std::deque的内存管理机制使其在两端操作时非常高效:
它内部使用多个固定大小的内存块(缓冲区)来存储元素。
每个缓冲区的大小通常与机器的页面大小(如4KB)对齐,以减少内存碎片。
插入和删除操作通常只需要在缓冲区的头部或尾部进行,而不需要像
std::vector那样频繁地重新分配整个内存。
这种设计使得std::deque在以下场景中非常有用:
需要频繁在两端插入和删除元素:如滑动窗口问题、任务调度等。
需要随机访问但又不希望像
std::vector那样频繁重新分配内存。
6. 使用场景
6.1 滑动窗口问题
std::deque常用于解决滑动窗口的最大值或最小值问题。通过维护一个单调队列,可以在O(1)时间内获取窗口内的最大值或最小值。
#include <deque>
#include <iostream>
#include <vector>std::vector<int> maxSlidingWindow(const std::vector<int>& nums, int k) {std::deque<int> dq; // 存储索引std::vector<int> result;for (int i = 0; i < nums.size(); ++i) {// 移除超出窗口范围的元素while (!dq.empty() && dq.front() <= i - k) {dq.pop_front();}// 移除所有小于当前元素的索引while (!dq.empty() && nums[dq.back()] < nums[i]) {dq.pop_back();}dq.push_back(i);// 当窗口形成后,记录最大值if (i >= k - 1) {result.push_back(nums[dq.front()]);}}return result;
}int main() {std::vector<int> nums = {1, 3, -1, -3, 5, 3, 6, 7};int k = 3;std::vector<int> result = maxSlidingWindow(nums, k);std::cout << "Max sliding window: ";for (int x : result) {std::cout << x << " ";}std::cout << std::endl;return 0;
}
6.2 回文检查
std::deque可以用于检查字符串或序列是否为回文。通过从两端同时读取元素,可以快速判断是否对称。
#include <deque>
#include <iostream>bool isPalindrome(const std::string& str) {std::deque<char> dq(str.begin(), str.end());while (dq.size() > 1) {if (dq.front() != dq.back()) {return false;}dq.pop_front();dq.pop_back();}return true;
}int main() {std::string str = "racecar";std::cout << str << " is palindrome? " << (isPalindrome(str) ? "Yes" : "No") << std::endl;return 0;
}
7. 性能对比
与
std::vector对比:
std::vector更适合随机访问,但在两端插入和删除时效率较低(尤其是前端操作)。
std::deque在两端操作时效率更高,但随机访问的效率略低于std::vector。与
std::list对比:
std::list支持在任意位置高效插入和删除,但不支持随机访问。
std::deque支持随机访问,且在两端操作时效率更高。
8. 总结
std::deque是C++ STL中一个非常强大且灵活的容器,适用于需要在两端频繁操作的场景。它结合了队列和栈的特点,同时支持随机访问,具有较高的通用性和效率。通过合理使用std::deque,可以简化代码逻辑并提高程序性能。
二、练习
例一、Problem - 6375


#include <deque>
#include <cstdio>
#include <iostream>
#include <algorithm>using namespace std;int main()
{int n, q; // n表示队列的数量,q表示操作的数量while (scanf("%d%d", &n, &q) != EOF) // 读取n和q,直到文件结束{deque<int> deq[n + 1]; // 创建n+1个双端队列(索引从0到n)for (int i = 0; i < q; i++) // 对每个操作进行循环{int a, u, w;scanf("%d%d%d", &a, &u, &w); // 读取操作类型a,以及参数u和wif (a == 1) // 如果操作类型是1,则执行插入操作{int value;scanf("%d", &value); // 读取要插入的值if (w == 0) // 根据w的值决定在队首还是队尾插入{deq[u].push_front(value); // 在队首插入}else {deq[u].push_back(value); // 在队尾插入}}else if (a == 2) // 如果操作类型是2,则执行查询并删除操作{if (!deq[u].empty()) // 确保队列非空{if (w == 0) // 根据w的值决定查询并删除队首还是队尾元素{printf("%d\n", deq[u][0]); // 打印队首元素deq[u].pop_front(); // 删除队首元素}else{printf("%d\n", deq[u].back()); // 打印队尾元素deq[u].pop_back(); // 删除队尾元素}}else {printf("-1\n"); // 如果队列为空,打印-1}}else // 操作类型为3时,先交换w和v的含义,然后根据w决定是否翻转队列v,并将v的所有元素移动到队列u中{int v = w; // 注意这里先读入的是v的实际值,即原先的wscanf("%d", &w); // 再次读取w的真实值if (w == 1 && deq[v].size() >= 2) // 如果需要翻转且队列v至少有两个元素{reverse(deq[v].begin(), deq[v].end()); // 翻转队列v}while (!deq[v].empty()) // 将队列v的所有元素移动到队列u{deq[u].push_back(deq[v].front()); // 把队列v的队首元素添加到队列u的队尾deq[v].pop_front(); // 移除队列v的队首元素}}}}return 0;
}

例二、 641. 设计循环双端队列 - 力扣(LeetCode)
设计实现双端队列。
实现
MyCircularDeque类:
MyCircularDeque(int k):构造函数,双端队列最大为k。boolean insertFront():将一个元素添加到双端队列头部。 如果操作成功返回true,否则返回false。boolean insertLast():将一个元素添加到双端队列尾部。如果操作成功返回true,否则返回false。boolean deleteFront():从双端队列头部删除一个元素。 如果操作成功返回true,否则返回false。boolean deleteLast():从双端队列尾部删除一个元素。如果操作成功返回true,否则返回false。int getFront()):从双端队列头部获得一个元素。如果双端队列为空,返回-1。int getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回-1。boolean isEmpty():若双端队列为空,则返回true,否则返回false。boolean isFull():若双端队列满了,则返回true,否则返回false。示例 1:
输入 ["MyCircularDeque", "insertLast", "insertLast", "insertFront", "insertFront", "getRear", "isFull", "deleteLast", "insertFront", "getFront"] [[3], [1], [2], [3], [4], [], [], [], [4], []] 输出 [null, true, true, true, false, 2, true, true, true, 4]解释 MyCircularDeque circularDeque = new MycircularDeque(3); // 设置容量大小为3 circularDeque.insertLast(1); // 返回 true circularDeque.insertLast(2); // 返回 true circularDeque.insertFront(3); // 返回 true circularDeque.insertFront(4); // 已经满了,返回 false circularDeque.getRear(); // 返回 2 circularDeque.isFull(); // 返回 true circularDeque.deleteLast(); // 返回 true circularDeque.insertFront(4); // 返回 true circularDeque.getFront(); // 返回 4提示:
1 <= k <= 10000 <= value <= 1000insertFront,insertLast,deleteFront,deleteLast,getFront,getRear,isEmpty,isFull调用次数不大于2000次
class MyCircularDeque {
private:vector<int> elements;int rear, front;int capacity;public:MyCircularDeque(int k) {capacity = k + 1;rear = front = 0;elements = vector<int>(k + 1);}bool insertFront(int value) {if (isFull()) {return false;}front = (front - 1 + capacity) % capacity;elements[front] = value;return true;}bool insertLast(int value) {if (isFull()) {return false;}elements[rear] = value;rear = (rear + 1) % capacity;return true;}bool deleteFront() {if (isEmpty()) {return false;}front = (front + 1) % capacity;return true;}bool deleteLast() {if (isEmpty()) {return false;}rear = (rear - 1 + capacity) % capacity;return true;}int getFront() {if (isEmpty()) {return -1;}return elements[front];}int getRear() {if (isEmpty()) {return -1;}return elements[(rear - 1 + capacity) % capacity];} bool isEmpty() {return rear == front;}bool isFull() {return (rear + 1) % capacity == front;}
};



相关文章:
C++双端队列知识点+习题
在C中,双端队列(Deque,发音为“deck”)是标准模板库(STL)中的一种容器适配器,其全称为Double-Ended Queue。它结合了队列和栈的特点,允许在容器的两端(前端和后端&#x…...
【递归、搜索和回溯算法】专题二 :二叉树中的深搜
二叉树中的深搜 深度优先遍历(DFS):一种沿着树或图的深度遍历节点的算法,尽可能深地搜索树或图的分支,如果一条路径上的所有结点都被遍历完毕,就会回溯到上一层,继续找一条路遍历。 在二叉树中…...
Vue3计算属性深度解析:经典场景与Vue2对比
一、计算属性的核心价值 计算属性(Computed Properties)是Vue响应式系统的核心特性之一,它通过依赖追踪和缓存机制优雅地解决模板中复杂逻辑的问题。当我们需要基于现有响应式数据进行派生计算时,计算属性总能保持高效的性能表现…...
UE5与U3D引擎对比分析
Unreal Engine 5(UE5)和Unity 3D(U3D)是两款主流的游戏引擎,适用于不同类型的项目开发。以下是它们的主要区别,分点整理: 1. 核心定位 UE5: 主打3A级高画质项目(如主机/P…...
【vue3学习笔记】(第150-151节)computed计算属性;watch监视ref定义的数据
尚硅谷Vue2.0Vue3.0全套教程丨vuejs从入门到精通 本篇内容对应课程第150-151节 课程 P150节 《computed计算属性》笔记 写一个简单的 姓、名输入框效果: 用vue2的形式定义一个计算属性 fullName: 测试页面展示无问题: 但是,在vue…...
JavaScript如何实现复制图片功能?
最近开发中遇到一个需求,就是用户希望能通过直接点击按钮复制图片,然后就可以很方便的把图片发送到班群中,于是就有了复制图片的需求。 那么如何通过JavaScript来实现复制图片呢? 一、前置知识:如何实现复制…...
MySQL 8 设置允许远程连接(Windows环境)
🌟 MySQL 8 设置允许远程连接(Windows环境) 在开发和部署应用时,经常需要从远程主机连接到MySQL数据库。默认情况下,MySQL仅允许本地连接,因此需要进行一些配置才能允许远程访问。今天,我将详细…...
我又又又又又又更新了~~纯手工编写C++画图,有注释~~~
再再再次感谢Ttcofee提的问题 本次更新内容: 鼠标图案(切换),版本号获取,输入框复制剪切板 提前申明:如果运行不了,请到主页查看RedpandaDevc下载,若还是不行就卸了重装。 版本号&…...
Python控制语句——循环语句-for
1.下面的语句哪个会无限循环下去()。 A、 for a in range(10): time.sleep(10) B、 while 1<10: time.sleep(10) C、 while True: break D、 a = [3,-1,2] for i in a: if i==-1: break 答案:B。1<10始终为True,循环体中又没有break的条件,故B会无限循环。 2.for s i…...
全面解析:将采购入库单数据集成到MySQL的技术实施
旺店通旗舰版-采购入库单集成到MySQL的技术案例分享 在数据驱动的业务环境中,如何高效、准确地实现系统间的数据对接是企业面临的重要挑战。本文将聚焦于一个具体的系统对接集成案例:将旺店通旗舰奇门平台上的采购入库单数据集成到MySQL数据库中&#x…...
12. Pandas :使用pandas读Excel文件的常用方法
一 read_excel 函数 其他参数根据实际需要进行查找。 1.接受一个工作表 在 11 案例用到的 Excel 工作簿中,数据是从第一张工作表的 A1 单元格开始的。但在实际场景中, Excel 文件可能并没有这么规整。所以 panda 提供了一些参数来优化读取过程。 比如 s…...
记录致远OA服务器硬盘升级过程
前言 日常使用中OA系统突然卡死,刷新访问进不去系统,ping服务器地址正常,立马登录服务器检查,一看磁盘爆了。 我大脑直接萎缩了,谁家OA系统配400G的空间啊,过我手的服务器没有50也是30台,还是…...
Java网络多线程
网络相关概念: 关于访问: IP端口 因为一个主机上可能有多个服务, 一个服务监听一个端口,当你访问的时候主机通过端口号就能知道要和哪个端口发生通讯.因此一个主机上不能有两个及以上的服务监听同一个端口. 协议简单来说就是数据的组织形式 好像是两个人交流一样,要保证自己说…...
【H2O2 | 软件开发】Axios发送Http请求
目录 前言 开篇语 准备工作 正文 概念 封装工具包 示例 结束语 前言 开篇语 本系列为短篇,每次讲述少量知识点,无需一次性灌输太多的新知识点。该主题文章主要是围绕前端、全栈开发相关面试常见问题撰写的,希望对诸位有所帮助。 如…...
VScode 运行LVGL
下载vscode解压 环境安装 安装mingw64,gcc 版本必须8.3以上 安装cmak 系统环境变量Path中添加(以实际安装目录为准) C:\Program Files\mingw64\bin C:\Program Files\CMake\bin 将GUI-Guider生成的代码目录拷贝一份放到vscode项目目录…...
AIP-165 按条件删除
编号165原文链接https://google.aip.dev/165状态批准创建日期2019-12-18更新日期2019-12-18 有时API需要提供一种机制,按照一些过滤参数删除大量资源,而非提供待删除的各资源名字。 这是一个稀有的场景,用于用户一次性删除数千或更多资源的…...
React Next项目中导入Echart世界航线图 并配置中文
公司业务要求做世界航线图,跑了三个ai未果,主要是引入world.json失败,echart包中并不携带该文件,源码的world.json文件页面404找不到。需要自己寻找。这是整个问题卡壳的关键点,特此贴出资源网址。 目录 一、安装 二…...
QT与网页显示数据公式的方法
一.网页中显示数学公式通常有三种主要方法 1.图片方式 原理:将公式转换为图片(如 PNG、SVG),通过 <img> 标签嵌入网页。 实现步骤: 使用工具(如 LaTeX dvipng、在线生成工具)将公式渲…...
深入解析APP订阅页的运作机制(订阅页如何运作)
在当今数字经济的背景下,订阅模式已成为许多企业获取稳定收入的重要方式。无论是软件、视频流媒体还是电子商务,订阅服务都能为用户提供持续的价值体验。然而,如何有效地设计和运作一个订阅页,是决定用户是否愿意订阅的关键因素。…...
Golang倒腾一款简配的具有请求排队功能的并发受限服务器
golang官方指南[1]给了一些代码片段,层层递进演示了信道的能力: 1>. 信号量2>. 限流能力 var sem make(chan int, MaxOutstanding) func Serve(queue chan *Request) {for req : range queue {req: reqsem <- 1 go func() { // 只会开启MaxOutstandin…...
【运维】服务器系统从centos7重装为ubuntu22.04
目录 一、硬盘准备二、系统安装三、安装基本系统组件四、挂载机械硬盘五、问题解决 一、硬盘准备 【注意:这一步会把硬盘的数据清空,所以需要找一个空的U盘或者把U盘数据备份】 ubuntu22.04下载 需要先安装 bittorrent 下载完之后会打开一个网页 然后…...
创新技术引领软件供应链安全,助力数字中国建设
编者按 随着数字化转型的加速,针对软件供应链的攻击事件呈快速增长态势,目前已成为网络空间安全的焦点。如何将安全嵌入到软件开发到运营的全流程,实现防护技术的自动化、一体化、智能化,成为技术领域追逐的热点。 悬镜安全作为…...
【设计模式】建造者模式——工厂模式
三、建造者模式——工厂模式 3.1 工厂模式 创建一个类对象的传统方式是使用关键字new, 因为用new 创建的类对象是一个堆对象,可以实现多态。工厂模式通过把创建对象的代码包装起来,实现创建对象的代码与具体 的业务逻辑代码相隔离的目的(将对象的创建和…...
Java基础:枚举类enum入门案例
1.基础枚举定义与使用: package com.zxy;public class Main {public static void main(String[] args) { // 获取枚举值cars car cars.BMW;switch (car){case BMW :System.out.println("BMW");break;case BENZ :System.out.println("BENZ&…...
蓝桥备赛(18)- 红黑树和 set 与 map(上)
对于二叉搜索树 , 平衡二叉树 , 以及红黑树 , 目前只需要了解背后的原理 , 不做代码实现的要求 , 重要的就是了解各种操作的时间复杂度即可 , 为set 与 map 做铺垫 一、二叉搜索树 1.1 基本概念 相较与于堆…...
Spring Boot集成EasyExcel
1. 初始化Spring Boot项目 首先,使用Spring Initializr(https://start.spring.io/)生成一个基本的Spring Boot项目。选择以下依赖项: Spring WebLombok (用于减少样板代码)SLF4J (用于日志记录) 2. 添加依赖 在你的pom.xml文件…...
obeaver 连接oracle 库 模式乱码
下载orai18n-12.1.0.2.0.jar 库--添加文件--把提前下载好的jar 随便放在一个文件夹下--添加文件选中,然后点击找到类, 选择类,确定即可正常 下载地址:https://download.csdn.net/download/weixin_42845364/88368302...
ChatGPT 使用教程:深度探索AI常用功能技巧
文章目录 前言一、ChatGPT介绍1.1 人工智能与自然语言处理的发展1.2 ChatGPT 的诞生与意义 二、ChatGPT 基础入门2.1 注册与登录2.2 对话界面介绍2.3 基本提问方式 三、常用功能详解3.1 文本生成3.2 问题回答3.3 语言翻译3.4 代码生成与调试 四、高级使用技巧4.1 指令优化4.2 多…...
無人機的應用程序有那些可以部署在linux server 系統
Dronecode Project:由 Linux Foundation 主導的開源項目,提供無人機航空操作系統和導航工具的開發框架,適合開發者使用。 DeepSeek-R1:這是一個人工智能模型,適用於無人機的數據處理和分析,支持在 Linux 系…...
[HUBUCTF 2022 新生赛]messy_traffic
下载附件 看到文件类型直接用wireshark打开,对MySQL协议进行追踪流,并没有什么发现,后面对NO.437发现有用信息,http追踪流 发现**system(‘cat passwd.txt’);**这里是在打开查看passwd.txt,密码是"SignUpForHUBU…...
