deque介绍

news2024/11/24 2:21:54

目录

简介:

初识deque

deque的底层实现

deque插入

deque的operator[]

deque的迭代器

deque的缺陷 

与vector比的缺陷

与list相比的缺陷

deque的优势


简介:

这一节不会进行模拟实现,只会聊聊deque的底层

原因是我们学习deque是为了后面的适配器打基础,deque本身并不重要 

初识deque

deque是一个双端队列,它是基于vector和list的优点为一身(但又不突出)

deque对头部数据进行处理时,时间复杂度会到达O(1)   弥补了vector的缺点

deque支持随机访问,也就是它支持了[]的重载,弥补了list的缺点

既然弥补了vector的缺点和list的缺点,那么为什么我们平时使用的时候好像没有使用过这个容器

不急,我们先看看deque的底层实现

deque的底层实现

deque插入

首先deque在实现时先有一段缓冲区(buffer)来存储数据

 可以看到,图上的缓冲区满了

deque的尾插规则就是

如果缓冲区没满,那么直接在缓冲区后面插入

如果缓冲区满了,那么就重新申请一个buffer并插入数据

 我们看到,buffer可能是存有多个的,既然有多个我们就需要对buffer进行管理

deque中就有了中控器

中控器是用来存储buffer指针的指针数组,我们直接用二级指针(因为中控也是要增容的)表示即可

deque头插的规则:

deque在进行头插的时候也是要重开一个buffer的

跟尾插不同的是,重新开的buffer进行头插时是从buffer的尾部开始插入的

例如,我们在上面图的基础上,先头插入一个0,再头插入一个-1

 以上就是deque的头插和尾插的原理,接下来我们看看它的随机访问是如何实现的

deque的operator[]

T& operator[](size_t n);

首先先判断n是否大于第一个buffer的数据

如果小于第一个buffer的数据,那么返回的就是第一个buffer对应n的位置的数据

如果大于第一个buffer的数据,计算规则如下

(n-第一个buffer的数据多少)/每个buffer的大小 = 对应数据所在的第几个buffer

(n-第一个buffer的数据多少)%每个buffer的大小 = 数据在buffer中对应的下标

注意:buffer对应的大小应该从0开始

如上图,我们计算一下[8]所对应的数据

(8-2)/8 =0

(计算出来的是第一个buffer之后第0个buffer,这个是从0开始的)

(8-2)%8 = 6

 (计算出来的6是对应buffer[6]所对应的数据)

最终,也就计算出了对应的数据在buffer1下标为6的位置也就是7

deque的迭代器

如图:

(节选自STL源码剖析) 

可以看到,deque的迭代器中有四个成员:cur、first、last、node,那他们对应的功能是什么呢?

cur:指向的数据

first:指向的是这段buffer所在的开始位置

last:指向的是这段buffer所在的结束位置

node:指向的是这段buffer在中控所对应的下标

可以看出,deque的迭代器其实是蛮复杂的

当我们进行++时,迭代器会进行判断,cur是否等于last

如果cur等于last,就让node指向下一个buffer,并把cur指向buffer的first

如果cur不等于last,就让cur指向下一个下标所对应的数据即可

deque的缺陷 

 既然我们在实际当中不经常使用deque,那么他肯定是有所缺陷的

正如它的优点是与vector和list相比,那么它的缺点肯定也是跟这两个容器相比

所谓成也萧何,败也萧何

与vector比的缺陷

首先我们比较一下它的随机访问和vector的随机访问

deque的随机访问是要通过计算的

vector的随机访问是通过下标直接找到,不需要计算

那么deque如果进行大量的随机访问,效率就会比vector慢很多很多 

我们写一个代码测试一下

#include<iostream>
#include<deque>
#include<vector>
#include<ctime>
using namespace std;
#define NUM 10000000 //10000000次随机访问


void TestDequeVector()
{
	deque<int> d;
	vector<int> v;
	srand((long long)time(nullptr));
	for (int i = 0; i < 10000; ++i)
	{
		int x = rand();
		d.push_back(x);
		v.push_back(x);
	}
	int begin1 = clock();
	for (int i = 0; i < NUM; ++i)
	{
		d[i % 10000]++;
	}
	int end1 = clock();
	cout << "deque:" << end1 - begin1 << endl;
	int begin2 = clock();
	for (int i = 0; i < NUM; ++i)
	{
		v[i % 10000]++;
	}
	int end2 = clock();
	cout << "vector:" << end2 - begin2 << endl;
}

int main()
{
	TestDequeVector();
	return 0;
}

与list相比的缺陷

虽然说deque的头部插入和list的头部插入都达到了O(1)

但他们两的区别在于中间插入

deque的中间插入是需要挪动数据的(因为如果扩容了小buffer,那么下标就无法进行访问了)

list的中间插入一如既往的稳定,时间复杂度还是O(1)

#include<iostream>
#include<list>
#include<deque>
#include<ctime>
using namespace std;
#define NUM 10000 //插入的数据
void TestDequeList()
{
	list<int> l;
	deque<int> d;
	//先插入100000个数据,不然不好统计中间插入
	for (size_t i = 0; i < 100000; ++i)
	{
		l.push_back(i);
		d.push_back(i);
	}
	size_t mid = 100000 / 2;
	list<int>::iterator lit = l.begin();
	deque<int>::iterator dit = d.begin();
	while (mid)
	{
		//找到中间数据
		++lit;
		++dit;
		mid--;
	}
	//从这里开始记录clock
	int begin1 = clock();
	for (size_t i = 0; i < NUM; ++i)
	{
		lit = l.insert(lit, 1);
	}
	int end1 = clock();
	cout << "list insert : " << end1 - begin1 << endl;

	int begin2 = clock();
	for (size_t i = 0; i < NUM; ++i)
	{
		dit = d.insert(dit, 1);
	}
	int end2 = clock();
	cout << "deque insert : " << end2 - begin2 << endl;
}

int main()
{
	TestDequeList();
	return 0;
}

 

deque的优势

1、空间利用率比起list较高

2、 与vector相比支持头插和尾插,且都达到了O(1)时间复杂度(作为适配器的主要条件)

3、与list相比无需频繁申请空间

4、与vector相比扩容代价小(空间满了以后只需扩容中控,中控一次扩容可以存放很多数据)

5、与vector相比空间浪费少

那么这期deque介绍就到这里了,感谢大家的支持 

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

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

相关文章

RabbitMQ中的AMQP协议与核心组成介绍

前言 在RabbitMQ中为了传输数据&#xff0c;使用的是基于TCP/IP协议构造的AMQP协议。RabbitMQ的核心组成部分包括&#xff1a;Server、Connection、Channel、Message、ExChange、Virtual Host、Bingings、Routing key、Queue AMQP协议 AMQP协议全称&#xff1a;Advanced Mes…

RK3588平台开发系列讲解(驱动基础篇)信号驱动 IO 实验

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、信号驱动 IO 简介二、实验程序2.1、应用程序2.2、驱动程序沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 信号驱动 IO 不需要应用程序查询设备的状态,一旦设备准备就绪,会触发 SIGIO 信号,进而调用注…

论文中文翻译——kAFL Hardware-Assisted Feedback Fuzzing for OS Kernels

本论文相关内容 论文下载地址——26th USENIX Security Symposium论文中文翻译——kAFL Hardware-Assisted Feedback Fuzzing for OS Kernels 文章目录 本论文相关内容前言kAFL&#xff1a;操作系统内核的硬件辅助反馈Fuzzing作者信息论文来源主办方信息摘要1 引言2 技术背景2…

系统U盘制作随记

随身系统U盘制作 最近花了好多时间&#xff0c;废了好多U盘才把这东西搞明白了。 主要是自己的笔记本问题比较多&#xff0c;用实验室的Hp机一下就弄好了。 用这篇博客总结一下自己&#xff0c;然后附上详细的流程以免大家踩坑。 Windows to Go 这个比较容易上手 1. 准备…

EIoT能源物联网在工厂智能照明系统改造项目的应用 安科瑞 许敏

【摘要】&#xff1a;随着物联网技术的发展&#xff0c;许多场所针对照明合理应用物联网照明系统&#xff0c;照明作为工厂的重要能耗之一&#xff0c;工厂的照明智能化控制&#xff0c;如何优化控制、提高能源的利用率&#xff0c;达到节约能源的目的。将互联网的技术应用到工…

MySQ基本操作详解

MySQL的基本操作 首先sql操作中的关键字的是大小写不敏感的&#xff0c;create 和CREATE是一样的。 1.库操作 1. 1查看数据库 show databases;show 和databases 之间有一个或者多个空格注意是databases而不是database结尾分号是英文形式&#xff0c;分号在SQL中是表示一行执…

第三节 循环结构

文章目录 1. while循环1.1 什么是循环?1.2 while 循环1.2.1 语法结构1.2.2 循环中的异类 1.3 while循环使用案例1.3.1 求1~100之间的和1.3.2 求1~100之间偶数之和1.3.3 循环中的"标志变量" 1.4 嵌套循环使用1.4.1 嵌套循环语法结构1.4.2 嵌套练习 1.5 知识扩展 --最…

Mobx+Mobx-React快速上手 简单可扩展的状态管理解决方案

Mobx是Redux之后的一个状态管理库&#xff0c;基于响应式状态管理&#xff0c;整体是一个观察者模式的架构&#xff0c;存储state的store是被观察者&#xff0c;使用store的组件是观察者。Mobx可以有多个store对象&#xff0c;store使用的state也是可以变对象&#xff0c;这些都…

LNMP架构搭建实操(终有弱水替沧海,再无相思寄巫山”大概意思就是,你会遇到很多人,但不会有人像我那么爱你了。)

文章目录 一、安装Nginx服务1.安装依赖包2.创建Nginx运行用户3.编译安装Nginx源码包4.优化路径便于使用5、添加 Nginx 系统服务 二、安装Mysql服务1.安装Mysql环境依赖包2.创建Mysql运行用户3.编译安装4.修改mysql配置文件5.更改mysql安装目录和配置文件的属主属组6.设置路径环…

【Leetcode】77 组合 | 掌握回溯的力量吧!

【1】限制&#xff1a;数字只能够使用一次。 77 组合 栗子&#xff0c;从 { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 } \{1,2,3,4,5,6,7,8,9,10\} {1,2,3,4,5,6,7,8,9,10}中选择4个数&#xff1a; 选择1&#xff0c;从 { 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 } \{2,3,4,5,6…

电力需求侧管理和电力负荷管理数字化解决方案 安科瑞 许敏

摘要&#xff1a;近年来全国用电负荷特别是居民用电负荷的快速增长&#xff0c;全国范围内夏季、冬季用电负荷“双峰”特征日益突出&#xff0c;恶劣气候现象多发增加了电力安全供应的压力。具有随机性、波动性、间歇性特征的可再生能源大规模接入电网对电力系统的稳定性带来新…

视频观看行为高级分析(大数据分析)

今天介绍一下我们的视频观看行为高级分析功能。 一、观看行为分析 观看行为分析&#xff0c;基于Polyv大数据分析&#xff0c;能够以秒为粒度展示观众如何观看您的视频。 视频观看热力图是单次观看行为的图形化表示&#xff0c;Polyv云点播视频的每一次播放&#xff0c;都会产…

基于jupyter的多分类问题练习

文章目录 练习3&#xff1a;多分类问题介绍1 多分类1.1 数据集1.2 数据可视化1.3 逻辑回归的向量化1.3.1 代价函数的向量化1.3.2 梯度的向量化1.3.3 正则化逻辑回归的向量化 1.4 多分类-分类器 1.5 使用分类器进行预测 总结 练习3&#xff1a;多分类问题 介绍 在本练习中&…

Leetcode周赛348

第一题&#xff1a;最小化字符串长度 思路分析 通过分析我们可以发现&#xff0c;只要存在重复的元素就可以继续进行操作所以这里本质上是一道去重的题目去重我们可以使用双指针算法和Set&#xff1b;我们选择使用Set进行去重 class Solution {public int minimizedStringLengt…

Vue2 vue-cli

安装与卸载vue脚手架 npm i -g vue/cli vue --version 查看vue脚手架版本 vue -V 查看vue脚手架版本 npm uninstall -g vue/cli 卸载 创建项目 vue create 项目名 选择项目 &#xff08;Default 为快速创建项目&#xff09; 选择最后一下&#xff0c;回车 上下键选择 Rou…

shell脚本:函数

shell脚本-函数 一、函数&#xff1a;1.定义&#xff1a;2.作用&#xff1a;3.格式&#xff1a; 二、函数传参&#xff1a;1.定义&#xff1a;2.函数变量&#xff1a;3.递归&#xff1a;4.函数库&#xff1a; 一、函数&#xff1a; 1.定义&#xff1a; &#xff08;1&#xf…

Internal error. Please report to https://jb.gg/ide/critical-startup-errors

大佬的解决方式&#xff1a;PyCharm 2023 启动报错的处理 部分同学&#xff0c;发现在安装 PyCharm 2023.1.2 以及 PyCharm 2023.2 的抢先体验版之后&#xff0c;运行的时候愣是直接弹出了类似上面的报错。 反正&#xff0c;别慌&#xff01; 是的&#xff0c;他们有 bug。 …

呈现视觉妙技:使用Python将MP4视频转化为迷人的GIF图像

前言 GIF图片对于我来说是一个很好的展示方式&#xff0c;GIF 图片能够展示动态的图像效果&#xff0c;对于展示计算机视觉算法或结果非常有用。例如&#xff0c;我可以使用 GIF 图片来展示运动跟踪、姿势识别、图像分割、目标检测等任务的结果&#xff0c;以更生动和直观的方…

基于midiepipe、opencv的家庭健身智能推荐与姿态监测系统

目录 0. 前言1. opencv简介2. midiepipe简介3. yolo5简介4. 虚拟环境搭建以及工程目录设置5. 部分代码展示6. 项目成果7. 说明 0. 前言 本项目由我与gay友以及三位21级学弟历时一年共同合作完成 为了给运动者提供一种更加科学、更加精准的个性化运动方案&#xff0c;设计实现…

【SpinalHDL快速入门】6.2、SpinalHDL语法之When/Switch/Mux

文章目录 1.1、When1.2、Switch1.2.1、实例1.2.2、附加选项 1.3、本地声明1.4、Mux1.5、位选择1.5.1、实例 1.1、When 与VHDL和Verilog一样&#xff0c;当满足指定条件时可以对信号进行有条件的赋值&#xff1a; when(cond1) {// Execute when cond1 is true }.elsewhen(cond…