C++STL之deque容器

2023-11-20

概述:
上一篇我们讲过queue容器,它是一个单向的队列,只能从尾部插入,头部删除。而本节讲的deque容器,它是一个双向的队列,在头尾均可以调用插入与删除,并且支持迭代器和迭代器随机访问,这是它与queue的最大区别。

实际上,deque容器的函数特性和vector容器更像,或者是几乎一样,即使queue和deque
都是队列,但实际上除了可以满足先进先出共性不大,因为queue不支持迭代器等操作。
下面给出关于vector容器的文章。对于我个人而言或者比较熟STL的人,可以只看两篇文章的总结。

https://blog.csdn.net/weixin_44517656/article/details/110292591

1 deque容器的遍历

非常简单,同样是使用迭代器遍历即可。

void printDeque(const deque<int>&d){
	// iterator 普通迭代器
	// reverse_iterator 反转迭代器
	// const_iterator   只读迭代器
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++){
		//*it = 10000; 只读,不能修改
		cout << *it << " ";
		//it=it+1; 支持迭代器随机访问
	}
	cout << endl;
}

2 deque的插入

2.1 简单使用deque的插入

void test01(){
	deque<int>d;
	//尾插
	d.push_back(10);
	d.push_back(20);
	d.push_back(30);
	//头插
	d.push_front(100);
	d.push_front(200);
	d.push_front(300);
	//insert插入
	d.insert(d.begin(), 400);

	printDeque(d);
}

结果:
在这里插入图片描述

2.2 测试deque容器的插入是否会造成迭代器失效

2.2.1 先测试push_back
测试代码。

void test02() {
	deque<int>d;
	//尾插
	d.push_back(10);
	d.push_back(20);
	d.push_back(30);
	//头插
	d.push_front(100);
	d.push_front(200);
	d.push_front(300);
	//d.resize(10);
	for (auto it = d.begin(); it != d.end(); it++) {
		if (*it == 200) {
			d.push_back(150);
		}
	}

	printDeque(d);
}

1)先获取迭代器首地址。
在这里插入图片描述
2)调用push_back函数后,虽然地址没有改变,但是系统会认为该片内存被修改过(插入元素了),将该迭代器置为非法,所以再使用就会报错,类似vector一样。
并且我也尝试在插入前给队列足够的空间即resize(10),防止内存不够而新开辟内存,但是仍然会报错,即无论是否内存足够,deque的插入操作都会造成迭代器失效,更深一层分析是因为它像vector一样,建立的方式为数组,地址是连续的,所以插入会失效。而list不会,因为list不是数组,地址不连续,地址是动态开辟的。
在这里插入图片描述
在这里插入图片描述

2.2.2 测试push_front
代码在测试push_back的if条件中改成push_front即可。即:

if (*it == 200) {
	//d.push_back(150);
	d.push_front(250);
}

1)先获取迭代器首地址。
在这里插入图片描述

2)调用push_front函数后,和调用push_back函数后的结果一样,同样会被系统置为非法,继续使用会造成迭代器失效。
在这里插入图片描述
在这里插入图片描述

2.2.3 测试insert
同样改一下上面代码即可。

		if (*it == 200) {
			//d.push_back(150);
			//d.push_front(250);
			d.insert(it, 150);
		}

1)先获取迭代器首地址。
在这里插入图片描述

2)调用insert函数后,和调用push_back,push_front函数后的结果一样,同样也会被系统置为非法,继续使用会造成迭代器失效。
在这里插入图片描述
在这里插入图片描述

2.3 总结deque容器的插入

  • 1)不管deque容器的内存是否足够,凡是调用了push_back,push_front,insert插入函数,都会造成迭代器失效。原因是因为使用数组创建,插入时内存地址是连续的,容易造成数据访问混乱,并且当内存不足时会被拷贝到新的内存地址中,故被系统标记为非法。类似vector。
  • 2)区别于list,因为list不是数组创建的,它的内存地址不是连续的,故调用push_back,push_front,insert这些插入函数时迭代器不会失效。

3 deque容器的删除

3.1 简单使用deque容器的删除

void test03() {
	deque<int>d;
	//尾插
	d.push_back(10);
	d.push_back(20);
	d.push_back(30);
	//头插
	d.push_front(100);
	d.push_front(200);
	d.push_front(300);

	/*因为我删除元素后并未继续使用迭代器,所以不需担心迭代器是否失效*/
	d.pop_back();
	d.pop_front();
	d.erase(d.begin());

	printDeque(d);
}

结果:
在这里插入图片描述

3.2 测试deque容器的删除是否会造成迭代器失效

3.2.1 测试deque容器的pop_back删除
1)先获取迭代器首地址。
在这里插入图片描述
2)调用pop_back函数后,可以看到迭代器没有改变,并且程序是能正常运行的,这是因为pop_back的删除并非删除地址未对内存地址做出改变,而是通过元素的前后移动进行删除的,所以调用pop_back后迭代器没有失效。
在这里插入图片描述
能正确打印结果:
在这里插入图片描述

3.2.2 测试deque容器的pop_front删除
1)先获取迭代器首地址。
在这里插入图片描述
调用pop_front函数后,迭代器地址未改变,并且继续运行程序也是正常的,说明迭代器并未失效。
在这里插入图片描述

3.2.3 测试deque容器的erase删除
测试代码同样改一下即可。

if (*it == 200) {
	//d.pop_back();   
	//d.pop_front();
	d.erase(it);
}

1)先获取迭代器首地址。
在这里插入图片描述

2)调用erase函数后,虽然迭代器地址仍一样,但是该地址已经改变了,所以再次使用该迭代器会报错,也就是说调用erase会使迭代器失效。
这里需要提醒一下:deque的pop_front,pop_back这些函数不会回收地址,而只是通过前后移动进行删除。而erase这个函数是会可以认为系统会回收地址导致迭代器失效不能再访问该内存地址。
在这里插入图片描述
在这里插入图片描述

3.3 总结deque的删除

  • 1)调用pop_back,pop_front函数后,迭代器地址未改变,并且继续运行程序也是正常的,说明迭代器并未失效。这是因为pop_back的删除并非删除地址并未对内存做出改变,而是通过元素的前后移动进行删除的,所以调用pop_back后迭代器没有失效。
  • 2)而调用erase函数删除后,虽然迭代器地址仍一样,但是该地址已经改变了,所以再次使用该迭代器会报错,也就是说调用erase会使迭代器失效。
    这里需要提醒一下:deque的pop_front,pop_back这些函数不会回收地址,而只是通过前后移动进行删除。而erase这个函数是会可以认为系统会回收地址导致迭代器失效不能再访问该内存地址。

4 总结deque的插入和删除

4.1 插入

  • 1)不管deque容器的内存是否足够(可以resize测试),凡是调用了push_back,push_front,insert插入函数,都会造成迭代器失效。原因是因为使用数组创建,插入时内存地址是连续的,容易造成数据访问混乱,并且当内存不足时会被拷贝到新的内存地址中,或者换种说话是deque的插入改变了内存地址结构,故被系统标记为非法。类似vector。
  • 2)区别于list,因为list不是数组创建的,它的内存地址不是连续的,故调用push_back,push_front,insert这些插入函数时迭代器不会失效。

4.2 删除

  • 1)调用pop_back,pop_front函数后,迭代器地址未改变,并且继续运行程序也是正常的,说明迭代器并未失效。这是因为pop_back的删除并非删除地址并未对内存做出改变,而是通过元素的前后移动进行删除的,所以调用pop_back后迭代器没有失效。(vector调用pop后继续使用迭代器也是不会报错的)
  • 2)而调用erase函数删除后,虽然迭代器地址仍一样,但是该地址已经改变了,所以再次使用该迭代器会报错,也就是说调用erase会使迭代器失效。
    这里需要提醒一下:deque的pop_front,pop_back这些函数不会回收地址,而只是通过前后移动进行删除。而erase这个函数是会可以认为系统会回收地址导致迭代器失效不能再访问该内存地址。

5 deque容器其它成员函数

5.1 deque构造函数
由于这些比较简单,直接伪代码了。

deque<T> deqT;//默认构造形式
deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身。
deque(n, elem);//构造函数将n个elem拷贝给本身。
deque(const deque &deq);//拷贝构造函数。

5.2 deque赋值操作

assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
deque& operator=(const deque &deq); //重载等号操作符
swap(deq);// 将deq与本身的元素互换

5.3 deque大小操作

deque.size();//返回容器中元素的个数
deque.empty();//判断容器是否为空
deque.resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除。

5.4 algorithm自带的算法sort排序

void test05(){
	//利用sort排序
	deque<int>d;
	d.push_back(10);
	d.push_back(20);
	d.push_back(30);
	d.push_back(40);
	d.push_front(100);
	d.push_front(200);
	d.push_front(300);
	d.push_front(400);

	//默认排序规则从小到大 算法里的sort()只支持随机访问的.故List自带sort()
	sort(d.begin(), d.end());
	printDeque(d);

	//从大到小排序
	sort(d.begin(), d.end(), [&](int a, int b) {return a > b; });

	printDeque(d);
}

结果。
在这里插入图片描述

6 关于deque的多线程测试

这里不再测试deque容器的多线程测试,因为知道这个容器的插入和删除相关函数的特性你就知道如何处理数据了。或者可以参考vector的测试,它们两个容器的共性可以说几乎一样。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++STL之deque容器 的相关文章

随机推荐

  • 推荐算法(Recommended Algorithms)

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • IBM Rational Rose2007 安装及故障处理

    因项目需要 最近需要安装IBM Rational Rose 在此过程中遇到一些问题 并简单记录下来 以帮助其他人来解决类似的问题 安装环境 WIN 10 Pro 软件版本 Rose 2007 安装路径 F Program Files x86
  • matlab中contourf函数怎么用_matlab中contour 函数的用法(绘制等高线)[图]

    matlab中contour 函数的用法 绘制等高线 图 08 11栏目 技术 TAG matlab等高线 matlab等高线 原文 contour 矩阵的等高线图 https www jhua org 全页折叠 https www jhu
  • zimg服务器搭建手记

    zimg是由国人开源的一个高性能的图片服务器 相关介绍和代码可从github上获取 https github com buaazp zimg 1 安装Openssl 这个很关键 必须先安装 wget http www openssl org
  • 程序员如何在春节假期避免加班?

    点击上方 程序人生 选择 置顶公众号 第一时间关注程序猿 媛 身边的故事 平日奋战在修复BUG前线的 IT界精英程序员们 马上就要开始新年假期了 平时加班忙成狗的你 今年过年想好怎么做才能不加班了么 回想2017年 那轰动全国的被迫加班 莫
  • 数据库系统概念-读写锁、意向锁、行表锁

    目录 1 MySql中的锁分类 2 读写锁和意向锁 共享锁 s 排他锁 X 意向共享锁 IS 和意向排他锁 IX 意向锁的作用 3 数据库行锁 表锁 封锁粒度 4 什么时候使用表锁 1 MySql中的锁分类 按照锁粒度分类 表锁和行锁 即这
  • emacs org-mode嵌入graphviz代码,并执行

    一 graphviz是一种依赖代码实现的画图工具 二 org mode是emacs里的一种文档编辑模式 堪称神器 三 org mode嵌入graphviz代码 并执行 意义 步骤 问题 一 graphviz是一种依赖代码实现的画图工具 特点
  • 2020年产品经理面试题-----产品经理面试题

    1 介绍一下你自己 介绍一下自己的姓名 年龄 毕业院校 工作经历 简单的介绍 保持在三分钟以内 给面试官问问题的时间 工作经历主要讲一些你牛逼的工作经历 例如 你加入XX公司以后 销售额增加了多少 用户翻了多少倍 这样一些 有些人工作经历比
  • webpack5 配置&使用 文档(大全)

    一 起步 1 基本安装 首先我们创建一个目录 初始化 npm 然后 在本地安装 webpack 接着安装 webpack cli 此工具用于在命令行中运行 webpack mkdir webpack demo cd webpack demo
  • 浅拷贝、深拷贝和写时拷贝

    浅拷贝 指对象在复制时 只对对象的数据成员进行简单地赋值 而不复制对象本身 新旧对象还是共享同一块内存即只是增加了一个指针指向已存在的内存地址 因为共享同一份资源 当一个对象将这份资源释放掉 而此时另一个对象并不知道该资源已经被释放 当再次
  • element ui 对话框el-dialog关闭事件,清空填写的数据

    原文链接 https blog csdn net rickiyeat article details 76595390 通常会有需求 在关闭弹框后需要清空填写的数据 这时候就需要关闭事件了
  • UE编辑器下简单把 excel格式的表格转换为wiki支持的表格

    觉得 wiki下 mediawiki 导入excel和word表格好麻烦 微软自带的offic插件wiki转换工具一直都安装不上 为了更新wiki内容只能手动来做了后来总结了以下手动方法 1 复制编辑好的Excel表格到记事本 用ue打开
  • 关于构造函数

    使用构造函数 两种使用构造函数的初始化方式 Stock food Stock World 250 1 25 等价于 Stock garment Furry 50 2 5 将构造函数与new一起使用 new可以调用构造函数 Stock pst
  • 利用input上传图片以及文件视频音频等

    这里说的input指的就是我们常用的
  • unity中创建询问弹出窗口

    在开发过程中进程会遇到需要弹出一个窗口询问用户是否进行的操作 今天就来制作一个这样弹出窗口 然后根据弹出窗口的选择内容不同进行不同的操作 本例中主要是为了删除一个数据 而在删除数据操作前需要得到用户的一个确认操作 这里面主要用到了Notif
  • 一个超级棒的VUE流程设计器--easy-flow开箱即用

    今天小编推荐一款流程设计器easy flow easy flow基于VUE ElementUI JsPlumb的流程设计器 通过 vuedraggable 插件来实现节点拖拽 功能介绍 支持拖拽添加节点 点击线进行设置条件 支持给定数据加载
  • JSON介绍及代码示例

    了解json JSON是什么 JSON是JavaScript Object Notation的缩写 它是一种数据交换格式 在JSON出现之前 大家一直用XML来传递数据 因为XML是一种纯文本格式 所以它适合在网络上交换数据 XML本身不算
  • MFC ListControl

    1 ListControl的基本创建 基本设置 m ListCtrl DeleteAllItems m ListCtrl InsertColumn 0 T NBA m ListCtrl InsertColumn 1 T Final Cham
  • office2010 卸载出现“安装程序找不到ProPlus.ww\ProPsWW.cab 请浏览正确的安装源的错”解决方法

    笔者在换电脑后想卸载office2010安装office2016 但是卸载的过程中遇到了上述问题就记录一下自己的解决方案 1 强制删除officeX对应的文件夹 然后使用toolkit工具清理即可 笔者是通过这种方法解决的 2 应该也可以使
  • C++STL之deque容器

    概述 上一篇我们讲过queue容器 它是一个单向的队列 只能从尾部插入 头部删除 而本节讲的deque容器 它是一个双向的队列 在头尾均可以调用插入与删除 并且支持迭代器和迭代器随机访问 这是它与queue的最大区别 实际上 deque容器