c++的STL(3)-- deque容器

目录

deque概述 

deque的内存模型 

注意: 

1. deque的默认构造(和vector类似)

 代码:

2. deque的有参构造(和vector类似)

 代码:

3. deque容器在首部和尾部添加或者元素

代码:

 相关知识点: 

4. deque容器的元素个数 (和vector类似)

 代码:

5.  deque在指定位置插入元素(和vector类似)

代码: 

相关知识点: 

6.deque容器元素的访问(和vector类似)

 代码:

7.  deque的迭代器(和vector使用方法是一样的)

8. deque容器删除元素(和vector类似) 

代码: 

相关知识点: 

 9.deque容器赋值(和vector类似)

代码: 

10.resize()修改元素个数(和vector中的类似)

11. deque()中的其它函数(和vector类似)

12. deque相对于vector函数的变动 

13. deque容器的注意事项 


 deque容器和vector容器的很多方法的使用都是类似的,如果一样就不在详述,请查看c++的STL(2)-- vector容器中的对应部分进行查看。

 如果要查看动态开辟空间内容以及注意事项,如何避免其带来的低效率。 以及reserve()和shrink_to_fit()函数的使用,请直接看vector容器中相关的内容。

deque概述 

  • deque是一个双端队列,内部是使用数组进行实现的,其内部的空间和vector容器不同,其空间并不一定是连续的。
  • deque在开头和尾部添加元素都是非常快的,但是deque在中间插入元素是很慢的,因为需要进行元素移动。 
  • deque可以也可以进行随机存取。

deque的内存模型 

通过建立 map 数组,deque 容器申请的这些分段的连续空间就能实现“整体连续”的效果。换句话说,当 deque 容器需要在头部或尾部增加存储空间时,它会申请一段新的连续空间,同时在 map 数组的开头或结尾添加指向该空间的指针,由此该空间就串接到了 deque 容器的头部或尾部。

有读者可能会问,如果 map 数组满了怎么办?很简单,再申请一块更大的连续空间供 map 数组使用,将原有数据(很多指针)拷贝到新的 map 数组中,然后释放旧的空间。

注意: 

鉴于deque的内存方式 -- 也就是存储数据的内存是不连续的,所以我们不能对deque中的数据使用指针进行访问。 --  应该使用迭代器。(迭代器是容器内嵌的类,进行了处理)

例子:

int main(void) {
	deque<int> d1{1,2,3,4,5};

	d1.emplace_front(6);

	int* a = &d1[1];
/*
	++a;
	cout << "a=" << *a << endl;
*/
	--a;
	cout << "a=" << *a << endl;

	system("pause");

	return 0;
}

代码中我们使用初始化列表,在d1容器中存放了5个元素,然后使用emplace_back()在其前面插入一个数据6。

按照上面的内存模型,我们知道存储6的空间和存储1-5的空间不是连续的。我们取1的地址存放到指针a当中,对a++之后,打印a中的数据是2。但是如果进行a--,打印a中的数据会发现时一串非法数字。

这就是因为1前面的6和他们不存储在同一片内存并且不连续,当a--的时候访问的是存储1的前一个内存,但是这里存储的并不是6而是一个垃圾值。

但是你会发现我们对a++,就可以正确的访问,这是因为1-5的空间是连续的,对a++后面的空间存储的是2。虽然这样可以,但是还是不要使用指针直接访问deque中的元素,因为你无法确定从哪里开始内存就不连续了,会有风险。

表  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() 的区别是,该函数直接在容器尾部构造元素,省去了复制移动元素的过程。

要想使用deque容器,需要导入头文件#include <deque> 

下面的知识点,如果和vector类似,那么只会给出代码,具体的知识点请看vector容器的那一节。

1. deque的默认构造(和vector类似)

 代码:

#include <iostream>
#include <stdlib.h>
#include <deque>

using namespace std;

class Student {

};

int main(void) {
	/*
	deque<int> d1;
	deque<float> d1;
	deque<Student> d1;
	deque<Student *> d1;
    deque<int *> d1;
	*/

	system("pause");

	return 0;
}

2. deque的有参构造(和vector类似)

 代码:

/*
  有参构造:
  方式一:  使用初始化列表  c++11之后支持
  deque<int> d1{ 1,2,3,4,5 };

  方式二:  初始化时指定元素个数
  deque<int> d1(10);  // 指定元素个数为10,并且只为默认值(此处为0)
  deque<int> d1(10,5);// 10个元素的值为5

  方式三:  使用指针(数组)
  int arr[] = { 1,2,3,4,5 };
  deque<int> d1(arr,arr+2); //  区间左闭右开,将arr数组的前两个元素放到d1中

  方式四:  使用其它deque的迭代器
  deque<int> d1{10,20,30,40,50};
  deque<int> d2(d1.begin(), d1.begin() + 2);  // 区间左闭右开,将d1容器的前两个元
                                              // 素放到d2中
  
  // 使用其它容器的迭代器
  vector<int> v1{ 1,2,3,4,5 };
  deque<int> d1(v1.begin(),v1.end());

  方式五:   调用拷贝构造函数
  deque<int> d1{10,20,30,40,50};
  deque<int> d2(d1);  // 将d1中的元素放到d2中
*/

3. deque容器在首部和尾部添加或者元素

在deque的首尾插入和删除元素都是很快的,在首部插入,它会再开辟一段空间来存放,所以也不需要移动元素。

代码:

/*
  deque<int> d1;
  1. 尾部添加:  push_back() , emplace_back();
  q1.push_back(1);
  q1.emplace_back(2);

  int a = 10;
  q1.push_back(a);
  q1.emplace_back(a);

  2. 尾部删除:  pop_back();
  q1.pop_back();

  3. 首部添加:  push_front() , emplace_front();
  q1.push_front(1);
  q1.emplace_front(2);

  int a = 10;
  q1.push_front(a);
  q1.emplace_front(a);

  4. 首部删除:  pop_front();
  q1.pop_front();

  添加元素时,在空间不够的时候,会开辟空间
  删除元素时不影响容器容量
*/
 相关知识点: 
  • push_front()和emplace_front()函数可以在deque容器的前面添加一个元素,而且很快。
  • pop_front()函数可以删除deque容器中最前面的元素。
  • 至于在尾部添加和删除元素和vector类似
  • emplace_front()好人push_front()的区别,请看vector中相关内容的讲解

4. deque容器的元素个数 (和vector类似)

 代码:

deque<int> q1{1,2,3,4,5};

cout << "q1容器的元素个数:" << q1.size() << endl; // 输出5

5.  deque在指定位置插入元素(和vector类似)

代码: 

/*
 deque<int> d1;
 deque在指定位置插入元素:
 方式一:  使用insert()
 1. d1.insert(d1.begin(), 5);  在开始位置插入5
 2. d1.insert(d1.begin(), 5,3); 在开始位置插入5个3
 3. d1.insert(d1.begin(), {1,2,3,4,5}); 在开始位置插入列表中的数据
 4. deque<int> d2{ 1,2,3,4,5 };
    d1.insert(d1.begin(), d2.begin()+1,d2.begin()+3); 在开始的位置插入[d2.begin()+1,d2.begin()+3)范围内的数据,范围为左闭右开

    vector<int> v1{ 1,2,3,4,5 };
    deque<int> d1;
    d1.insert(d1.begin(), v1.begin(), v1.end()); // 将v1中的元素插入到d1的开始位置

 5. int arr[] = { 1,2,3,5,4 };
    d1.insert(d1.begin(), arr+1,arr+3); 在开始位置插入指针[arr+1,arr+3)范围(左闭右开)内的数据。(也就是数组中的第二个元素)

 方式二:  使用emplace()
 d1.emplace(d1.begin(), 5);  在开始的位置插入5

 在空间不够的时候,两种方式都会开辟空间
*/
相关知识点: 
  • insert()在插入单个元素和多个元素的时候,返回的是插入位置的迭代器。(不同的编译器实现可能不一样)
  • 已经在vector中展示过 

6.deque容器元素的访问(和vector类似)

 代码:

/*
deque<int> d1{1,2,3,4,5};
deque的元素访问:
1. 使用[]:
   d1[0] = 10;
   cout << d1[2] << endl;
2. 使用at():
   d1.at(1) = 5;
   cout << d1.at(1) << endl;
3. 使用front()访问第一个元素
   d1.front() = 100;
   cout << d1.front() << endl;
4. 使用back()访问最后一个元素
   d1.back() =  50;
   cout << d1.back() << endl;
*/

7.  deque的迭代器(和vector使用方法是一样的)

 

 

至于迭代器的用法和vector是很类似的,此处就不在演示了。

8. deque容器删除元素(和vector类似) 

代码: 

/*
  deque<int> d1{1,2,3,4,5};
  deque删除元素:
  1. 使用erase()
     (1) d1.erase(d1.begin()); // 删除d1开始位置的元素
	 (2) d1.erase(d1.begin(), d1.begin() + 2); // 删除迭代器区间[beg,end)内的元素,左闭右开的范围
  2. 使用clear()
     d1.clear()  // 删除所有的元素

   两者都不修改容器容量
*/
相关知识点: 
  • erase()函数在删除单个元素和多个元素的时候,都会返回被删除元素的下一个元素的迭代器。
  • 上面的使用,以及erase()使用的注意事项,和与循环结合删除元素时的注意事项,在vector中已经详细说明。 

 9.deque容器赋值(和vector类似)

代码: 

/*
  deque<int> d1{1,2,3,4,5};
  deque赋值操作:
  使用assign()
  1. d1.assign(5,1);  // 使用5个1覆盖容器中的原来数据
  2. deque<int> d2{10,11,12,13,14,15}; 
     d1.assign(d2.begin(), d2.end()); // 使用d2中的迭代器范围[beg,end)中的元素覆盖原有数据
  3. int  arr[] = { 1,2,3,4,5 };  // 使用指针[ptr1,ptrt2)中的元素覆盖原来数据
     d1.assign(arr, arr + 2);
  4. d1.assign({ 5,6,7,8,9 }); // 使用列表中的数据覆盖原来数据

  使用赋值运算符重载
  d1 = d2;   // 使用d2中的值覆盖原来数据

  assign在空间不够的时候,会开辟空间
*/

10.resize()修改元素个数(和vector中的类似)

请看vector中的实现。 

11. deque()中的其它函数(和vector类似)

  •  swap() 函数可以交换两个deque容器的元素,并且会交换两个容器的容量
  • max_size() 函数会返回可以存储最大的元素数量。--> 并不是返回多少就一定能存储多少元素,得看电脑内存大小,编译器等因素都有影响。
  • empty() 函数可以判断容器中的元素个数是否为0,若为0返回true。

12. deque相对于vector函数的变动 

  • 增加了专门在首部添加元素和删除元素的函数。
  • 删除了data(),reserve(),capacity()这三个函数。 

13. deque容器的注意事项 

  • 在涉及到范围的时候,都是左闭右开的。
  •  初始化列表在c++11中新增的,如果不支持c++11那么就不能使用。(就是使用{}的地方,除数组之外)
  • deque中可以存放bool类型,vector中不可以存放。
  • size_type和value_type和vector中使用类似。
  • 29
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值