• Deque容器的系列操作( 详解 )



    一、Deque容器简介

    Vector容器是单向开口的连续内存空间,deque则是一种双向开口的连续线性空间,又称双端动态数组。所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,当然,vector容器也可以在头尾两端插入元素,但是在其头部操作效率奇差,无法被接受。
    在这里插入图片描述
    与vector容器的区别

    Deque容器和vector容器最大的差异:

    1. deque允许使用常数项时间对头端进行元素的插入和删除 操作。

    2. deque没有容量的概念,因为它是动态的以分段连续空间组合而成,随时可以增加一段新的空间并链接起来,换句话说,像vector那样,”旧空间不足而重新配置一块更大空间,然后复制元素,再释放旧空间”这样的事情在deque身上是不会发生的。也因此,deque没有必须要提供所谓的空间保留(reserve)功能. 虽然deque容器也提供了Random Access Iterator,但是它的迭代器并不是普通的指针, 其复杂度和vector不是一个量级,这当然影响各个运算的层面。

    因此,除非有必要,我们应该尽可能的 使用vector,而不是deque。对deque进行的排序操作,为了最高效率,可将deque先完整的复制到一个vector中,对vector容器进行排序,再复制回deque。

    deque容器的实现原理

    Deque容器是连续的空间,至少逻辑上看来如此,连续现行空间总是令我们联想到array和vector,array 无法成长,vector虽可成长,却只能向尾端成长,而且其成长其实是一个假象,事实上
    (1) 申请更大空间
    (2)原数据复制新空间
    (3)释放原空间
    三步骤,如果不是vector每次配置新的空间时都留有余裕,其成长假象所带来的代价是非常昂贵的。 Deque是由一段一段的定量的连续空间构成。一旦有必要在deque前端或者尾端增加新的空间,便配置一段连续定量的空间,串接在deque的头端或者尾端。Deque最大的工作就是维护这些分段连续的内存空间的整体性的假象,并提供随机存取的接口,避开了重新配置空间,复制,释放的轮回,代价就是复杂的迭代器架构。 既然deque是分段连续内存空间,那么就必须有中央控制,维持整体连续的假象,数据结构的设计及迭代器的前进后退操作颇为繁琐。Deque代码的实现远比vector或list都多得多。 Deque采取一块所谓的map(注意,不是STL的map容器)作为主控,这里所谓的map是一小块连续的内存空间,其中每一个元素(此处成为一个结点)都是一个指针,指向另一段连续性内存空间,称作缓冲区。缓冲区才是deque的存储空间的主体。
    在这里插入图片描述

    二、基本操作

    1. 构造函数

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

    2. 赋值操作

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

    3. 大小操作

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

    4. 删除和插入

    push_back(elem);//在容器尾部添加一个数据 
    push_front(elem);//在容器头部插入一个数据 
    pop_back();//删除容器最后一个数据 
    pop_front();//删除容器第一个数据
    
    • 1
    • 2
    • 3
    • 4

    5. 数据存取

    at(idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range。 
    operator[];//返回索引idx所指的数据,如果idx越界,不抛出异常,直接出错。 
    front();//返回第一个数据。
    back();//返回最后一个数据
    
    • 1
    • 2
    • 3
    • 4

    6. 排序操作

    	//排序  默认排序规则 从小到大 升序
    	//对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序
    	//vector容器也可以利用sort进行排序
    	sort(d1.begin(),d1.end()); 
    
    • 1
    • 2
    • 3
    • 4

    三、代码实现

    1. 构造函数

    	deque<int> d;
    	for(int i=9;i>=0;i--)
    	{
    		d.push_front(i);
    	}
    	PrintDeque(d);
    	
    	deque<int>d2(d.begin(),d.end());    //区间赋值 
    	PrintDeque(d2);
    	
    	deque<int>d3(10,100);       //赋值 10个100 
    	PrintDeque(d3);       
    	
    	deque<int>d4(d3);       //拷贝构造 
    	PrintDeque(d4);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2. 赋值操作

    	deque<int> d1;  //默认构造
    	for(int i=0;i<10;i++)
    	{
    		d1.push_back(i);           //后插入数值 
    	} 
    	printDeque(d1);
    	
    //赋值 operator=
    	deque<int> d2;
    	d2=d1; 
    	printDeque(d2);
    	
    //assign
    	deque<int> d3;
    	d3.assign(d1.begin(),d1.end());    //利用assign区间方式(左闭右开)  将d1赋值给d3    
    	printDeque(d3);
    	
    //n个elem方式赋值
    	deque<int> d4;
    	d4.assign(10,100);        //10个100赋值给d4 
    	printDeque(d4); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3. 大小操作

    deque<int> d1;  //默认构造
    	for(int i=0;i<10;i++)
    	{
    		d1.push_back(i);           //后插入数值 
    	} 
    	printDeque(d1);
    	
    	if(d1.empty())    //为真 代表容器为空
    	{
    		cout<<"d1为空"<<endl;
    	}
    	else
    	{
    		cout<<"d1不为空"<<endl;
    		cout<<"d1的大小为:"<<d1.size()<<endl;
    	}
    	
    //重新指定大小
    	d1.resize(15,1);     //利用重载版本,可以指定默认填充值  这里设定的大小长度为15,长出的部分用1填充(不设定的话,默认用0填充) 
    	printDeque(d1);
    	
    	d1.resize(5);       //设定的大小长度为5 
    	printDeque(d1);   //如果重新指定的长度比原来短了,超出部分会删除掉 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4. 删除和插入

    deque<int> d1;
    
    //插入操作 
    	//尾插
    	d1.push_back(10); 
    	d1.push_back(20); 
    	//头插
    	d1.push_front(100); 
    	d1.push_front(200);      
    	
    	// 200 100 10 20
    	PrintDeque(d1);
    	
    //删除操作
    	//尾删
    	d1.pop_back();
    	// 200 100 10
    	PrintDeque(d1);
    	//头删
    	d1.pop_front();
    	//100 10
    	PrintDeque(d1);	
    	
    //insert插入
    	d1.insert(d1.begin(),1000);    //在头部插入1000 
    	// 1000 100 10
    	PrintDeque(d1);
    	
    	d1.insert(d1.begin(),2,10000);    //在头部插入俩个10000 
    	// 10000 10000 1000 100 10
    	PrintDeque(d1); 
    	
    //按照区间进行插入
    	deque<int> d2;
    	d2.push_back(1); 
    	d2.push_back(2);
    	d2.push_back(3);
    	d1.insert(d1.begin(),d2.begin(),d2.end());    //在d1的头部插入 区间[d2.begin(),d2.end()] 
    	// 1 2 3 10000 10000 1000 100 10
    	PrintDeque(d1); 
    
    
    //删除操作 
    	deque<int> d1;
    	
    	d1.push_back(10); 
    	d1.push_back(20); 
    	d1.push_front(100); 
    	d1.push_front(200);  
    	
    //删除
    	deque<int> ::iterator it=d1.begin();
    	it++;   //即it指向第二个数
    	d1.erase(it);   //删除it指向的这个数
    	//  200 10 20
    	PrintDeque(d1);
    //按区间方式删除
    	d1.erase(d1.begin(),d1.end());    //删除d1的全部数据
    	
    //清空
    	d1.clear();
    	PrintDeque(d1); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    5. 数据存取

    deque<int> d1;
    	
    	d1.push_back(10); 
    	d1.push_back(20); 
    	d1.push_front(100); 
    	d1.push_front(200); 
    	
    	//利用[]方式访问数组元素
    	for(int i=0;i<d1.size();i++)
    	{
    		cout<<d1[i]<<" ";
    	}
    	cout<<endl;
    	
    	//利用at方式访问元素
    	for(int i=0;i<d1.size();i++)
    	{
    		cout<<d1.at(i)<<" ";
    	} 
    	cout<<endl;
    	
    	//获取第一个元素
    	cout<<"第一个元素为:"<<d1.front()<<endl;
    	
    	//获取最后一给元素
    	cout<<"最后一个元素为:"<<d1.back()<<endl; 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    6. 排序操作

    	deque<int> d1;
    
    	d1.push_back(10); 
    	d1.push_back(20); 
    	d1.push_front(100); 
    	d1.push_front(200);      
    // 200 100 10 20
    	cout<<"排序前:"<<endl;
    	PrintDeque(d1);
    	
    	//排序  默认排序规则 从小到大 升序
    	//对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序
    	//vector容器也可以利用sort进行排序
    	sort(d1.begin(),d1.end()); 
    	cout<<"排序后:"<<endl;
    	PrintDeque(d1);  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    目标检测YOLO实战应用案例100讲-基于改进YOLOv5的口罩人脸检测
    一家公司做了两年软件测试,只会功能测试,现在已经感到危机感了,那如何摆脱困境呢?
    Shell编程之免交互
    超详细的文件上传和下载(Spring Boot)
    依赖的注入
    matlab逐像元计算栅格数据10年间的变化趋势代码
    蓝桥杯练习
    ctfshow-web5(md5弱比较)
    现代卷积网络实战系列 总目录
    【 大数据分析Hadoop + Spark 】10分钟搭建Hadoop(伪分布式 )+ Spark(Local模式)环境
  • 原文地址:https://blog.csdn.net/Dustinthewine/article/details/125879736