【C++ STL】-- deque与vector相比的优势与劣势

news2024/11/30 6:52:17

目录

deque容器

与stack相比deque的优缺点:

deque的迭代器

deque的成员函数


deque容器

deque的相关文档

        deque与vector十分的相识。vector是单向开口的连续线性空间(单向扩容),deque则是一种双向开口的连续线性空间(双向扩容)。双向开口:可以在头尾两端分别做元素的插入和删除操作。区别就在此,vector当然也可以在头尾两端进行操作,但是其头部操作的效率奇差,无法被接受,如:stack与queue的容量适配器就在二者其中,选择deque(当然使用vector也可)

vector与deque的差异:

  • deque允许于常数时间内对头端进行元素的插入或移除操作。
  • deque没有所谓的容量观念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并连接起来。

与stack相比deque的优缺点:

优势:

  • 头尾插入删除很方便

劣势:

  • operator[]计算稍显复杂,大量使用,性能下降(下标需要经过计算)。
  • 中间插入删除效率不高(下标需要经过计算,并且需要挪动元素)。
  • 底层角度迭代器会很复杂。

结论:

  • 头尾的插入删除deque非常适合,相比vector而言,很适合去做stack和queue的默认适配容器。
  • 中间插入删除少用deque,可以用:list(因为无需挪动元素)。
  • 随机访问多用vector(因为下标是确定的)。

deque的迭代器

        需要注意,deque是连续的空间,但是这只是其逻辑上的,物理上并不是。所以在迭代器上维持其“整体连续”假象的工作,就落在迭代器中的operator++与operator--上了。

        首先,连续重要的就是能够指出分段空间在哪里,其次,它必须能够判断自己是否已经处于其所在的存储边缘,如果是,一旦前行或后退时就必须跳跃到下一个或上一个存储空间。

// __deque_iterator的源码
template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator
{
	typedef __deque_iterator<T, T&, T*>             iterator;
	typedef __deque_iterator<T, const T&, const T*> const_iterator;
	static size_t buffer_size() {return __deque_buf_size(0, sizeof(T)); }//buffer_size()用于确定缓冲区的大小
 
	typedef random_access_iterator_tag iterator_category;
	typedef T value_type;
	typedef Ptr pointer;
	typedef Ref reference;
	typedef size_t size_type; // size_t 是unsigned 类型,通常用来指明数组长度
	typedef ptrdiff_t difference_type; // ptrdiff_t 是 signed 整型,通常用来保存两个指针减法操作的结果
	typedef T** map_pointer;
 
	typedef __deque_iterator self;
 
	// 保持与容器的联结,是对某一个缓冲区而言的
	T* cur;       // 此迭代器所指之缓冲区中的现行元素
	T* first;     // 此迭代器所指之缓冲区的头
	T* last;      // 此迭代器所指之缓冲区的尾(含备用空间)
	map_pointer node;    // 指向管控中心
        ...
}

//deque_buf_size()全局函数
inline size_t deque_buf_size(size_t n, size_t sz){
    return n != 0 ? n : (sz < 512 ? size_t(512 / sz) : size_t(1));
}
//定义:
//1. 如果n不为0,传回n,表示buffer size由使用者自定。
//2. 如果n为0,表示buffer size使用默认值,那么:
//    如果sz不小于 512,返回1。
//    如果sz(元素大小,sizeof(value_type))小于512,传回512/sz。

void set_node(map_pointer new_node) {
	node = new_node;
	first = *new_node;
	last = first + difference_type(buffer_size());
}
reference operator*() const { return *cur; }
pointer operator->() const { return &(operator*()); }
difference_type operator-(const self& x) const {
	return difference_type(buffer_size()) * (node - x.node - 1) + (cur - first) + (x.last - x.cur);
}

self& operator++() {
	++cur;        //切换至下个元素
	if (cur == last) {   //如果已达所在缓冲区的尾端,就切换至下一节点(亦即缓冲区)的第一个元素
		set_node(node + 1);
		cur = first;
	}
	return *this;
}

self operator++(int) { //后置式,标准写法
	self tmp = *this;
	++*this;
	return tmp;
}

self& operator--() {
	if (cur == first) {//如果已达所在缓冲区的头端, 就切换至前一节点(亦即缓冲区)的最后一个元素
		set_node(node - 1);
		cur = last;
	}
	--cur; //切换至前一个元素
	return *this;
}

self operator--(int) { //后置式,标准写法
	self tmp = *this;
	--*this;
	return tmp;
}

// 以下实现随机存取。迭代器可以直接跳跃n个距离
self& operator+=(difference_type n) {
	difference_type offset = n + (cur - first);
	if (offset >= 0 && offset < difference_type(buffer_size()))
		//标的位置在同一缓冲区内
		cur += n;
	else {
		//标的位置不在同一缓冲区内
		difference_type node_offset =
			offset > 0 ? offset / difference_type(buffer_size()) : -difference_type((-offset - 1) / buffer_size()) - 1;

		// 切换至正确的节点(亦即缓冲区)
		set_node(node + node_offset);
		// 切换至正确的元素
		cur = first + (offset - node_offset * difference_type(buffer_size()));
	}
	return *this;
}

self operator+(difference_type n) const {
    self tmp = *this;
    return tmp += n; //调用operator+=
}

//利用operator+=完成operator-=
self& operator-=(difference_type n) { return *this += -n; }

self operator-(difference_type n) const {
    self tmp = *this;
    return tmp -= n; //调用operator-=
}

//实现随机存取,迭代器可以直接跳跃n个距离
reference operator[] (difference_type n) const { return * (*this + n);)}

bool operator==(const self& x) const { return cur == x.cur; }
bool operator!=(const self& x) const { return !(*this == x); }
bool operator<(const self& x) const {
    return (node == x.node) ? (cur < x.cur) : (node < x.node);
}

deque的成员函数

函数成员函数功能
begin()返回指向容器中第一个元素的迭代器。
end()返回指向容器最后一个元素所在位置后一个位置的迭代器,通常和 begin() 结合使用。
rbegin()返回指向最后一个元素的迭代器。
rend()返回指向第一个元素所在位置前一个位置的迭代器。
cbegin()和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
cend()和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crbegin()和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crend()和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
size()返回实际元素个数。
max_size()返回容器所能容纳元素个数的最大值。这通常是一个很大的值,一般是 232-1,我们很少会用到这个函数。
resize()改变实际元素的个数。
empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。
shrink _to_fit()将内存减少到等于当前元素实际所使用的大小。
at()使用经过边界检查的索引访问元素。
front()返回第一个元素的引用。
back()返回最后一个元素的引用。
assign()用新元素替换原有内容。
push_back()在序列的尾部添加一个元素。
push_front()在序列的头部添加一个元素。
pop_back()移除容器尾部的元素。
pop_front()移除容器头部的元素。
insert()在指定的位置插入一个或多个元素。
erase()移除一个元素或一段元素。
clear()移出所有的元素,容器大小变为 0。
swap()交换两个容器的所有元素。
emplace()在指定的位置直接生成一个元素。
emplace_front()在容器头部生成一个元素。和 push_front() 的区别是,该函数直接在容器头部构造元素,省去了复制移动元素的过程。
emplace_back()在容器尾部生成一个元素。和 push_back() 的区别是,该函数直接在容器尾部构造元素,省去了复制移动元素的过程。

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

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

相关文章

GIC/ITS代码分析(9)中断应用实例之IPI中断

PPI中断为外设私有中断&#xff0c;在ARM64上arch_timer为PPI中断。这里以arch_timer为例&#xff08;代码位置drivers/clocksource/arm_arch_timer.c&#xff09;&#xff0c;作应用实例讲解。 先对ARM64通用定时器作简要介绍。通用定时器为Arm core提供标准定时器。通用定时器…

VSCode下载安装与使用教程

目录1. 打开官网进行下载安装2. 下载3. 安装4. 使用4.1 python extensions4.2 建立 python 工作区4.3 运行python代码的 3 种方法方法一&#xff1a;点击按钮方法二&#xff1a;右键菜单方法三&#xff1a;交互式解释器5. debug参考资料VSCode是一款免费开源的现代化轻量级代码…

【C++修炼之路】8. string类详解

每一个不曾起舞的日子都是对生命的辜负 C之string类本节目标1. string类概览1.1 string的由来1.2 string函数列表2.string常用接口1. 初始化2. string::npos3. c_str()4. 获取长度&#xff08;length、size)5. 容量&#xff08;size、capacity)6. 插入&#xff08;insert)7. 替…

牛客网-《刷C语言百题》第三期

✅作者简介&#xff1a;嵌入式入坑者&#xff0c;与大家一起加油&#xff0c;希望文章能够帮助各位&#xff01;&#xff01;&#xff01;&#xff01; &#x1f4c3;个人主页&#xff1a;rivencode的个人主页 &#x1f525;系列专栏&#xff1a;《C语言入门必刷百题》 &#x…

【HTML5期末大作业】制作一个简单HTML我的班级网页(HTML+CSS+JS)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

微信小程序 |从零实现酷炫纸质翻页效果

&#x1f4cc;个人主页&#xff1a;个人主页 ​&#x1f9c0; 推荐专栏&#xff1a;小程序开发成神之路 --【这是一个为想要入门和进阶小程序开发专门开启的精品专栏&#xff01;从个人到商业的全套开发教程&#xff0c;实打实的干货分享&#xff0c;确定不来看看&#xff1f; …

保姆级透明背景动画导出 —— json格式(Mac系统)

日常能想到的小动画基本就是使用ps导出GIF动画/AE通过插件直接导出GIF&#xff0c;方便快捷&#xff1b;但最近工作中遇到了关于透明背景导出GIF动画的问题&#xff1a;导出的GIF动画有白边&#xff0c;有锯齿感。 网上找了一大堆教程&#xff0c;主要原因出在GIF格式本身的问…

黑马程序员Java实战项目--- ATM系统

项目介绍与功能演示 黑马银行ATM系统技术选型分析&#xff1a; 学习本项目&#xff0c;你将至少得到如下收获&#xff1a; 1、优秀的面向对象编程能力。 2、 清晰、缜密的业务、数据分析能力。 3、熟练使用程序流程技术来控制计算机完成自己的想法。 4、形成良好的编码习惯…

【面试题】移除数组删除重复项合并数组

1️⃣ 原地移除数组中所有的元素val 【OJ链接】 2️⃣ 删除排序数组中的重复项 【OJ链接】 3️⃣ 合并两个有序数组 【OJ链接】 1️⃣ 原地移除数组中所有的元素val 题目要求是要在数组中&#xff0c;把指定的数字全部去除&#xff0c;题目中也是强调了空间复杂度要求为O(1)&am…

项目经理要“谋定而后动,知止而有得,万事皆有法,不可乱也”

出自《大学》&#xff0c;“谋定而后动&#xff0c;知止而有得”的含义为谋划准确周到而后行动&#xff0c;知道目的地&#xff08;合适的时机收手&#xff09;才能够有所收获。 谋定而后动是告诉我们做任何事一定要进行谋划部署&#xff0c;做好准备&#xff0c;我们才能开始行…

数据结构作业:时间复杂度和二叉树

计算时间复杂度&#xff1a; int x0,i,j; 1 for(i1;i<n;i) n { for(j1;j<2*i;j) 2(n-1) { x; 2(n-1)*n } } 2(n-1)*n2n^2-2n 修改后的运行次数函数中&#xff0c;只保留最高阶项。 所以时间复杂度为 &#xff1a;…

老生常谈的商城系统(Asp.Net+uniapp)

真正的大师,永远都怀着一颗学徒的心&#xff01; 最近几天合肥是真热 这时候就应该宅在家里 吃着西瓜 啃着鸭脖 喝着啤酒 刷着剧 想想也太美好了吧 哈哈 我得醒醒 写完这篇推荐 吃吃喝喝去了 一、项目简介 今天推荐一款商城系统&#xff0c;虽然比较老生常谈了&#xff0…

【项目】若依框架如何实现批量导入,并解析出表中内容返回给前端? - poi依赖

文章目录实现效果&#xff1a;具体实现步骤&#xff1a;扩展实例内容&#xff1a;poi工具包ExcelHandlerAdapter接口ExcelUtil.java代码controllerserviceserviceImplmapper.javamapper.xmlTnProductProperty.java实现效果&#xff1a; 点击“导入excl”按钮 --> 弹出“文件…

MSDC 4.3 接口规范(27)

MSDC 4.3 接口规范&#xff08;27&#xff09;7.4.4 代码7.4.5 更新组呼业务7.4.5.1 接口函数7.4.5.2 先决条件7.4.5.3 说明7.4.5.4 调用流程7.4.6 其他信息通知7.4.6.1 组呼服务停止7.4.6.1.1 接口函数7.4.6.1.2 先决条件7.4.6.1.3 说明7.4.6.1.4 调用流程7.4.6.2 SAI 列表更新…

Nginx禁止文件下载防止服务器被恶意扫描

比如将网站数据库导出到站点根目录进行备份&#xff0c;很有可能也会被别人下载&#xff0c;从而导致数据丢失的风险。以下规则可以防止一些常规的文件被下载&#xff0c;可根据实际情况增减。我们可以通过以下俩种方法来防止服务器被恶意扫描&#xff0c;其中以彼之道&#xf…

ffmpeg解复用FLV文件

该博文是基于&#xff1a; ffmpeg&#xff1a;V 5.1.2 FLV格式是H2.64视频和aac音频复用得到的格式&#xff0c;我们所说的FLV解复用就是将FLV格式的数据的H2.64视频帧和aac音频帧分离。 分离完成后&#xff0c;音频是纯数据无法播放&#xff0c;需要添加ADTS头&#xff0c;视频…

浅谈基于以太网的煤矿电力监控系统的设计与应用

王兰 安科瑞电气股份有限公司 上海嘉定 201801 摘 要&#xff1a;针对传统煤矿电力监控系统通讯网络性能较差、无法实现准确故障定位及报警、不具备数据交互功能等问题&#xff0c;结合分布式网络及GPS授时技术设计了一套基于工业以太网及RS485总线架构的煤矿电力监控系…

第二十三课.扩散模型

目录概述前向过程逆向过程DDPM概述 近几年扩散模型不断涌现&#xff0c;但都来源于一个基础模型&#xff1a;DDPM&#xff08;Denoising Diffusion Probabilistic Model&#xff09;。扩散模型本质是生成模型&#xff0c;过去我们常用的生成模型包括GAN和VAE&#xff0c;利用随…

【Linux】冯诺依曼体系结构

目录&#x1f308;前言&#x1f337;1、冯诺依曼体系结构&#x1f338;2、操作系统(Operator System)&#x1f339;2.1、概念&#x1f340;2.2、如何理解管理&#x1f341;3、进程&#x1f342;3.1、概念&#x1f308;前言 本篇文章进行操作系统中进程的学习&#xff01;&…

全新一代智慧园区数字孪生解决方案,为园区运营商和集成商赋能!

对于园区运营方而言&#xff0c;园区既要满足使用者的需求&#xff0c;还要面对后期运营过程中大量、繁琐的维护管理工作&#xff0c;同时还要兼顾园区运维效率和管理成本。 随着5G、物联网、云计算、人工智能、大数据等技术的快速发展和应用&#xff0c;园区运维智能化升级已…