<C++> STL_deque

<c++> STL_deque

1.deque的使用

deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和 删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tp0r6ALo-1693144180150)(C:\Users\32784\AppData\Roaming\Typora\typora-user-images\image-20230827212550686.png)]

构造和析构

  • std::deque<T>:创建一个存储类型为 T 的元素的双端队列。
  • std::deque(const std::deque<T>& other):复制构造函数,用另一个双端队列初始化当前队列。
  • ~std::deque():析构函数,释放内存。

示例:

#include <iostream>
#include <deque>int main() {// 创建一个存储整数的双端队列std::deque<int> myDeque;// 在队尾插入元素myDeque.push_back(10);myDeque.push_back(20);myDeque.push_back(30);// 复制构造一个新的双端队列std::deque<int> anotherDeque = myDeque;// 输出原始队列的内容std::cout << "Original deque content:";for (const int& value : myDeque) {std::cout << " " << value;}std::cout << std::endl;// 输出复制构造的队列的内容std::cout << "Copied deque content:";for (const int& value : anotherDeque) {std::cout << " " << value;}std::cout << std::endl;// 注意:析构函数会在作用域结束时自动调用,释放内存return 0;
}

容量相关

  • size():返回队列中元素的数量。
  • empty():检查队列是否为空。

示例:

#include <deque>
#include <iostream>int main() {std::deque<int> myDeque = {10, 20, 30, 40};std::cout << myDeque.size() << std::endl; //4std::cout << myDeque.empty() << std::endl;//0return 0;
}
  • resize(new_size):调整队列的大小。
void resize(size_type count); 
void resize(size_type count, const value_type& value);
  • count:新的队列大小。
  • value:在增加队列大小时用于填充新元素的默认值。

功能:

  • 如果 count 小于当前队列的大小,resize 会移除尾部的元素,使队列的大小变为 count
  • 如果 count 大于当前队列的大小,resize 会在尾部插入足够数量的默认值为 value 的元素,使队列的大小变为 count

示例:

#include <iostream>
#include <deque>int main() {std::deque<int> myDeque = {10, 20, 30};// 调整队列大小为 5,填充默认值 0myDeque.resize(5);for (const int& value : myDeque) {std::cout << " " << value;   // 10 20 30 0 0}std::cout << std::endl;// 调整队列大小为 3myDeque.resize(3);for (const int& value : myDeque) {std::cout << " " << value;  // 10 20 30}std::cout << std::endl;return 0;
}

元素访问

  • at(index):函数返回指定索引处的元素,并在访问之前进行范围检查。如果索引超出了双端队列的有效范围,将引发 std::out_of_range 异常。
  • operator[](index):运算符返回指定索引处的元素,但不进行范围检查。如果索引超出了有效范围,行为将是未定义的。
  • front():返回第一个元素的引用。
  • back():返回最后一个元素的引用。

示例:

#include <deque>
#include <iostream>int main() {// 创建一个存储字符串的双端队列std::deque<std::string> myDeque;// 在队尾插入元素myDeque.push_back("Alice");myDeque.push_back("Bob");myDeque.push_back("Charlie");// 使用 at(index) 进行范围安全的访问try {std::string value = myDeque.at(1);// 索引1处的元素是 "Bob"std::cout << value << std::endl;  //Bob} catch (const std::out_of_range &e) {std::cout << "Index is out of range." << std::endl;}// 使用 operator[](index) 进行不安全的访问std::string unsafeValue = myDeque[2];// 索引2处的元素是 "Charlie"std::cout << "不安全: " << unsafeValue << std::endl;// 使用 front() 访问第一个元素std::string firstElement = myDeque.front();std::cout << firstElement << std::endl;// 使用 back() 访问最后一个元素std::string lastElement = myDeque.back();   //Alicestd::cout << lastElement << std::endl;      //Charliereturn 0;
}

修改操作

  • push_back(value):在队尾插入一个元素。
  • push_front(value):在队首插入一个元素。
  • pop_back():移除队尾的元素。
  • pop_front():移除队首的元素。
  • insert(pos, value):在指定位置插入一个元素。
  • erase(pos):移除指定位置的元素。
  • clear():移除所有元素。

示例:

#include <deque>
#include <iostream>int main() {std::deque<int> myDeque;// 在队尾插入元素myDeque.push_back(10);myDeque.push_back(20);// 在队首插入元素myDeque.push_front(5);// 输出队列内容for (const int &value: myDeque) {std::cout << value << " ";//5 10 20}std::cout << std::endl;// 移除队尾的元素myDeque.pop_back();// 移除队首的元素myDeque.pop_front();// 输出队列内容for (const int &value: myDeque) {std::cout << value << " ";//10}std::cout << std::endl;// 在指定位置插入元素std::deque<int>::iterator it = myDeque.insert(myDeque.begin() + 1, 15);// 输出队列内容for (const int &value: myDeque) {std::cout << value << " ";//10 15}std::cout << std::endl;// 移除指定位置的元素myDeque.erase(it);// 输出队列内容for (const int &value: myDeque) {std::cout << value << " ";//10}std::cout << std::endl;// 清空队列myDeque.clear();if (myDeque.empty()) {std::cout << "Deque is empty.";} else {std::cout << "Deque is not empty.";}std::cout << std::endl;return 0;
}

迭代器

  • begin()end():返回指向第一个元素和尾后元素的迭代器。

示例:

#include <iostream>
#include <deque>int main() {std::deque<int> myDeque = {10, 20, 30, 40};for (std::deque<int>::iterator it = myDeque.begin(); it != myDeque.end(); ++it) {std::cout << " " << *it;  //10 20 30 40}std::cout << std::endl;return 0;
}
  • rbegin()rend():返回指向最后一个元素和首元素前一个位置的逆向迭代器。

示例:

#include <iostream>
#include <deque>int main() {std::deque<int> myDeque = {10, 20, 30, 40};for (std::deque<int>::reverse_iterator rit = myDeque.rbegin(); rit != myDeque.rend(); ++rit) {std::cout << " " << *rit;   //40 30 20 10}std::cout << std::endl;return 0;
}

2.deque的原理介绍

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:

在这里插入图片描述

双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示:

在这里插入图片描述

那deque是如何借助其迭代器维护其假想连续的结构呢?

在这里插入图片描述

3.deque的优缺点

与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是比vector高的。 与list比较,其底层是连续空间空间利用率比较高,不需要存储额外字段。 但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构 时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作为stack和queue的底层数据结构。

4.为什么选择deque作为stack和queue的底层默认容器

stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。但是STL中对stack和queue默认选择deque作为其底层容器,主要是因为:

  1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
  2. 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。

结合了deque的优点,而完美的避开了其缺陷。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/56783.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一生一芯9——ubuntu22.04安装valgrind

这里安装的valgrind版本是3.19.0 下载安装包 在选定的目录下打开终端&#xff0c;输入以下指令 wget https://sourceware.org/pub/valgrind/valgrind-3.19.0.tar.bz2直至下载完成 解压安装包 输入下面指令解压安装包 tar -xvf valgrind-3.19.0.tar.bz2.tar.bz2注&#xf…

Keepalived+Lvs(dr)调度器主备配置小实验

目录 前言 一、实验拓扑图 二、配置LVS&#xff08;dr&#xff09;模式 三、配置调配器热备 四、测试 总结 前言 Keepalived和LVS&#xff08;Linux Virtual Server&#xff09;是两个常用的开源软件&#xff0c;通常结合使用以提供高可用性和负载均衡的解决方案。 Keepalive…

身为程序员,你有哪些提高写代码效率的工具?

首先&#xff0c;每个程序员都是会利用工具的人&#xff0c;也有自己囊里私藏的好物。独乐乐不如众乐乐&#xff0c;今天笔者整理了3个辅助我们写代码的黑科技&#xff0c;仅供参考。如果你有更好的工具&#xff0c;欢迎评论区分享。 1、Google/Stackoverflow——搜索解决方案的…

【运维】linux安装oracle客户端、安装mysql

文章目录 一. 下载二. 配置1. 配置环境变量2. 配置tnsnames.ora文件 三. 测试1. 链接语法2. 连接测试 四. 通过rpm安装mysql 一. 下载 下载地址 基础包 连接工具 二. 配置 上传、解压、配置环境变量 这里安装在/data01目录下 unzip instantclient-sqlplus-linux.x64-19.2…

Spring Boot(Vue3+ElementPlus+Axios+MyBatisPlus+Spring Boot 前后端分离)【三】

&#x1f600;前言 本篇博文是关于Spring Boot(Vue3ElementPlusAxiosMyBatisPlusSpring Boot 前后端分离)【三】的分享&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我…

keepalived+lvs(DR)

目录 一、作用 二、安装 1、在192.168.115.3 和192.168.115.4 上安装ipvs和keepalived&#xff1a; 2、配置keepalived 3、查看lvs节点状态 4、web节点配置 5、在web节点上调整ARP参数 6、配置虚拟IP地址与添加回环路由 7、配置nginx网页文档 8、启动服务 9、测试 一…

上位机采集8通道模拟量模块数据

模拟量模块和上位机的配合使用可以实现对模拟量数据的采集、传输和处理。下面是它们配合使用的一般步骤&#xff1a;1. 连接模拟量模块&#xff1a;将模拟量模块与上位机进行连接。这通常涉及将模拟量模块的输入通道与被监测的模拟信号源连接起来&#xff0c;如传感器、变送器等…

14. Docker中实现CI和CD

目录 1、前言 2、什么是CI/CD 3、部署Jenkins 3.1、下载Jenkins 3.2、启动Jenkins 3.3、访问Jenkins页面 4、Jenkins部署一个应用 5、Jenkins实现Docker应用的持续集成和部署 5.1、创建Dockerfile 5.2、集成Jenkins和Docker 6、小结 1、前言 持续集成(CI/CD)是一种…

18-使用钩子函数判断用户登录权限-登录前缀

钩子函数的两种应用: (1). 应用在app上 before_first_request before_request after_request teardown_request (2). 应用在蓝图上 before_app_first_request #只会在第一次请求执行,往后就不执行, (待定,此属性没调试通过) before_app_request # 每次请求都会执行一次(重点…

【Three.js + Vue 构建三维地球-Part One】

Three.js Vue 构建三维地球-Part One Vue 初始化部分Vue-cli 安装初始化 Vue 项目调整目录结构 Three.js 简介Three.js 安装与开始使用 实习的第一个任务是完成一个三维地球的首屏搭建&#xff0c;看了很多的案例&#xff0c;也尝试了用 Echarts 3D地球的模型进行构建&#xf…

设计模式中的关系

文章目录 一、依赖概念 二&#xff0c;关联概念 三、聚合概念 四、组合概念 五、实现概念 六、继承概念 图总结整体总结 一、依赖 概念 依赖是一种临时使用关系&#xff0c;代码层体现为作为参数。 具体体现&#xff1a;依赖者调用被依赖者的局部变量、参数、静态方法&#…

docker项目实战

目录 1、使用mysql:5.6和 owncloud 镜像&#xff0c;构建一个个人网盘。 1&#xff09;拉取mysql:5.6和owncloud镜像 2&#xff09;后台运行容器 3&#xff09;通过ip:端口的方式访问owncloud 2、安装搭建私有仓库 Harbor 1&#xff09;首先准备所需包 2&#xff09;安装h…

Lua与C++交互(一)————堆栈

Lua与C交互&#xff08;一&#xff09;————堆栈 Lua虚拟机 什么是Lua虚拟机 Lua本身是用C语言实现的&#xff0c;它是跨平台语言&#xff0c;得益于它本身的Lua虚拟机。 虚拟机相对于物理机&#xff0c;借助于操作系统对物理机器&#xff08;CPU等硬件&#xff09;的一…

HTML番外篇(四)-HTML5新增元素-CSS常见函数-理解浏览器前缀-BFC

一、HTML5新增元素 1.HTML5语义化元素 在HMTL5之前&#xff0c;我们的网站分布层级通常包括哪些部分呢&#xff1f; header、nav、main、footer ◼ 但是这样做有一个弊端&#xff1a; 我们往往过多的使用div, 通过id或class来区分元素&#xff1b;对于浏览器来说这些元素不…

雅思作文复习

目录 我使用的词汇&#xff1a; 上升&#xff1a; 下降&#xff1a; 波动&#xff1a; 保持&#xff1a; 幅度 大变化&#xff1a; 小变化&#xff1a; 雅思评价标准改变 小作文一般花费20分钟&#xff0c;我觉得自己能在18分钟解决是最好 考生在雅思考试中的小作文&a…

嵌入式系统存储体系

一、存储系统概述 主要分为三种&#xff1a;高速缓存&#xff08;cache&#xff09;、主存和外存。 二、高速缓存Cache 高速缓冲存储器中存放的是当前使用得最多得程序代码和数据&#xff0c;即主存中部分内容的副本&#xff0c;其本身无自己的地址空间。在嵌入式系统中Cac…

别在说自己不知道docker了,全文通俗易懂的给你说明白docker的基础与底层原理

docker介绍 Docker 是一个开源的应用容器引擎&#xff0c;基于Go语言进行开发实现并遵从Apache2.0 协议开源&#xff0c;基于 Linux 内核的 cgroup&#xff0c;namespace&#xff0c;以及 OverlayFS 类的 Union FS 等技术&#xff0c;对进程进行封装隔离&#xff0c;属于 操作…

Redis.conf详解

Redis.conf详解 配置文件unit单位对大小写不敏感 包含 网络 bind 127.0.0.1 # 绑定的ip protected-mode yes # 保护模式 port 6379 # 端口设置通用 GENERAL daemonize yes # 以守护进程的方式运行 默认为no pidfile /var/run/redis_6379.pid #如果以后台的方式运行&#xff…

python+django+mysql旅游景点推荐系统-前后端分离(源码+文档)

系统主要采用Python开发技术和MySQL数据库开发技术以及基于OpenCV的图像识别。系统主要包括系统首页、个人中心、用户管理、景点信息管理、景点类型管理、景点门票管理、在线反馈、系统管理等功能&#xff0c;从而实现智能化的旅游景点推荐方式&#xff0c;提高旅游景点推荐的效…

javaee idea创建maven项目,使用el和jstl

如果使用el表达式出现下图问题 解决办法 这是因为maven创建项目时&#xff0c;web.xml头部声明默认是2.3&#xff0c;这个默认jsp关闭el表达式 办法1 在每个需要用到el和jstl的页面的上面加一句: <% page isELIgnored"false" %> 方法2 修改web.xml文件开…