首页 > 编程语言 >C++ deque容器

C++ deque容器

时间:2024-10-23 19:45:58浏览次数:8  
标签:插入 deque 迭代 容器 C++ 访问 vector 底层

deque

deque是C++STL库中的一个容器,常用来当stack、queue的适配器。在算法领域中,适用于解决单调队列单调栈等问题。下面我们就来认识一下deque容器。

文章目录

1. vector与list区别

vectorlist
底层结构动态顺序表,一段连续空间带头结点的双向循环链表
随机访问支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素效率O(N)
插入和删除任意位置插入和删除效率低,需要挪动元素,时间复杂度为O(N),插入时有可能需要扩容,扩容:开辟新空间,拷贝元素,释放旧空间,导致效率更低任意位置插入和删除效率高,不需要挪动数据,时间复杂度为O(1)
空间利用率底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低
迭代器原生态指针对原生态指针(节点指针)进行封装
迭代器失效在插入元素时,要给所有的迭代器重新赋值,因为插入元素有可能会导致重新扩容,致使原来迭代器失效,删除时,当前迭代器需要重新赋值否则会失效插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响
使用场景需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随机访问

那么有没有一种数据结构可以结合上面两者的优点设计出一种可以随机访问并且不需要经常的进行重新扩容操作,并且弥补顺序表头插头删困难数据结构。——这个数据结构就是双端队列(deque)

2. deque的介绍和使用

2.1 deque的介绍

deque的文档介绍

deque吸取了vector的随机迭代器,支持 ++ -- + - 操作,访问某个数据的效率可以达到O(1),并且使用方便,大多数接口与vector一致

deque称之为双端队列,顾名思义就是支持两端插入删除的特殊队列,所以deque一般也是运用经常头插头删和尾插尾删的场景。

2.2 deque的使用

下面就举几个最常见,并且适合deque使用的接口(大多数和vector、list用法一致)

2.2.1 数据访问(Element access):
函数声明接口说明
operator[]同数组类似的访问
front返回头部数据引用
back返回尾部数据引用
2.2.2 增删改查(Modifiers):
函数声明接口说明
push_back尾插
push_front头插
pop_back尾删
pop_front头删

这里重点讲着四种接口主要缘由是deque一般情况就适合这四种操作(效率高,时间复杂度O(1)),当然也支持insert、erase等操作(效率极低,不推荐使用)。

3. deque底层实现

3.1 deque底层结构

3.1.1 deque结构

在这里插入图片描述

利用指针数组的概念将各个数组的地址存储在一个数组中,这样可以大大节约重新扩容的成本,只需要要将指针数组进行扩容然后拷贝各个指针就行了。

对指针数组的概念模糊的可以看这篇文章——深入理解指针(2)-CSDN博客

3.1.2 iterator(迭代器)结构
struct _deque_iterator
{
    T* cur;
	T* first;
 	T* last;
  	map_pointer node;
};
遍历方式:

先从begin()如图start的位置开始,然后对cur进行++后移,当 cur==last ,就将 node++ 并且first、cur、last迭代到该node上的属性,直到 cur == finish.cur

3.2 deque 随机访问

如果一个数组中存储n个数据对象

如果我们想要访问第 32 个数据,很简答的方法就是将 32 / n 就是 node的相对位置,32 % n 就是其与 该node 的first 的相对位置

3.3 头插尾插

3.3.1 尾插

尾插操作就是将end()如图finish迭代器,如果 cur == last 那就检查指针数组是否还有空间存储后插指针,如果没有进行重新扩容,然后存储数据 cur++

3.3.2 头插

头插就是尾插向前,独特的是在数组中插入数据是从 last 往 first 填(从右往左)。

3.4 insert/erase处理

insert和erase都需要大量的挪动数据,那么这里就有两种方式可以达到挪动数据的目的

  1. 保持每个数组的大小相同,这就需要整个deque的数据进行挪动

    优点:随机访问效率高、遍历效率高

    缺点:挪动数据量大

  2. 不需保持每个数组的大小相同,那我们就只需要对进行insert/erase位置所在的数组进行挪动(可能需要扩容)

    优点:挪动数据量相对小

    缺点:牺牲了随机访问和遍历的效率

实际上大多数编译器的源码实现都采用第一种方式。

4. deque的应用场景

4.1 deque的缺陷

优势:

  1. 与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素

  2. 与list比较,其底层是连续空间,空间利用率比较高,缓存利用率高,不需要存储额外字段。

  3. 头插头删以及尾插尾删效率高

缺陷:

  1. 不适合遍历,因为在遍历时,deque的迭代器要频繁的去检查其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list。
  2. 不适合中间插入和删除
  3. 虽然是随机迭代器,支持算法库中的sort,但是实际的效率却不如将其拷贝给vector再用vector进行排序,再重新拷贝会deque

4.2 deque的应用场景

  1. 用来帮助某些算法的实现,如单调队列单调栈等。

  2. STL用其作为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的优点,而完美的避开了其缺陷。

感谢你的支持,喜欢本文记得点赞收藏噢。

标签:插入,deque,迭代,容器,C++,访问,vector,底层
From: https://blog.csdn.net/Alenenen/article/details/143171355

相关文章

  • C++ STL基本用法概述(简洁版)
    vector变长数组,倍增思想基本函数 size()   //返回元素个数,时间复杂度为o(1)empty()   //返回a是否为空,时间复杂度为o(1)clear()   //清空front()/back()   //返回第一个数/最后一个数push_back()   //最后插入一个数pop_back()   //删掉最后一个数......
  • (分享源码)计算机毕业设计必看必学 上万套实战教程手把手教学JAVA、PHP,node.js,C++、pyth
    摘 要大数据时代下,数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化安全的要求,利用互联网服务于其他行业,促进生产,已经是成为一种势不可挡的趋势。在网络小说的要求下,开发一款整体式结构的小说网站,将复杂的系统进行拆分,能够实现对需求的变化快速响应、系统稳定性的保......
  • 计算机毕业设计项目推荐,基于协同过滤算法的短视频推荐系统设计与实现30213(开题答辩+程
    摘 要现阶段,社会的发展和科技的进步,以及大数据时代下纷繁数据信息的融合,使得人们在生产及生活过程中,都将会接收到各种类型的数据信息,而通过计算机技术与网络技术,则能够将众多人们所不了解或不常用的信息,以简单的模式转化并传递给人们,使得人们的生产及生活质量得以显著提升......
  • 计算机毕业设计项目推荐:基于Web的社区人员管理系统的设计36303(开题答辩+程序定制+全套
    摘要科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流,人类发展的历史正进入一个新时代。在现实运用中,应用软件的工作规则和开发步骤,采用ASP.NET技术建设社......
  • C++多线程同步和加锁的方式
    多线程同步和加锁的方式1.互斥锁(Mutex)互斥锁是一种常见的线程同步机制,用于保护共享资源,确保同一时间只有一个线程可以访问该资源。C++标准库提供了std::mutex类来实现互斥锁。std::mutex的lock()成员函数获取锁,使用完毕后调用unlock()释放锁。推荐使用std::lock_guard......
  • C++实现stack功能
    C++代码实现stack功能,具体代码如下:#include"stdafx.h"#include<iostream>#include<vector>#include<stdexcept>//forstd::out_of_rangetemplate<typenameT>classStack{private: std::vector<T>elements;//底层容器,用于存......
  • C++试题带答案
    阅读以下程序,回答问题1.试写出下列程序的输出结果与功能。 输出:2   sunny  24功能:求所有同学中年龄最大的同学2.试写出下列程序中函数fun()的功能及程序的输出结果。 函数fun()的功能:实现整数m的逆向输出程序的输出结果:543213.简述String类中Setc、Getc和Append三......
  • c++计时器
    c++计时器鼠标版#include<bits/stdc++.h>#include<windows.h>#definekd(vk)(GetAsyncKeyState(vk)&0x8000?1:0)usingnamespacestd;#defineSHAKE30voidShakeWindow(){ RECTrect; HWNDhwnd=GetConsoleWindow(); GetWindowRect(hwnd,&rect);......
  • C++刷题tricks整理
    是自己做题中整理的常用C++操作,此为存档。STL容器容器适配器,STL里面的vector/array/deque/set/map/unordered_set可以直接使用==比较是否相等:vector<int>a;deque<int>a;map<int,string>a;unordered_map<int,string>a;set<int>a;unordered_set<int>a;forward_lis......
  • 马拉车算法(C/C++)
    #1024程序员节|征文#马拉车算法(Manacher'sAlgorithm)是一种用于在字符串中查找最长回文子串的线性时间复杂度算法。该算法由UdiManacher在1980年代提出,因此得名。它的核心思想是利用已知的回文信息来减少不必要的比较,从而提高效率。算法步骤预处理字符串:为了处理奇数......