C++ std::deque

  • 重点deque: double-end queue,双端队列
  • std::deque 不像序列式容器那样将元素存储在连续的内存中,而是采用多个连续的存储块,在一个映射结构中对这些内存块及顺序进行跟踪。
  • 优点支持[ ]操作符和at()。首尾两端的pushpop操作为O(1),支持其他位置插入和删除操作O(n) 。对于长序列数据,扩容代价低。
  • 缺点:内存占用较多。


1. 底层原理

1.1 基础结构

  std::deque 结构上是一种双向开口的连续线性空间。可以在其头尾两端进行元素的插入和删除操作,当然,vector 也可以在头尾两端插入元素,但是在其头部操作效率非常低。std::dequevector不同点在于:

  • vector 使用单个数组,需要偶尔重新分配以进行增长。如对于非常长的序列,vector重新分配内存代价非常高。
  • deque是动态的以分段的内存块组合而成,随时可以增加一段新的内存空间拼接起来,因此不能保证其中所有元素存储在相邻的存储区域:通过指针偏移操作来访问deque中元素的行为,会导致访问出错。但这也使得deque可在某些情况下扩容代价更低(如非常长的序列)。

在这里插入图片描述

1.2 存储空间

  上面提到deque内部是分段的连续内存空间,为了将内存空间链接在一起、以及支持随机访问,其内部包含一个有 中控器 (map数组)。中控器中是一块小的连续空间,其中每个元素都是一个指针,每一个指针指向一段连续的内存空间(缓冲区),缓冲区才是deque的储存空间主体,结构如下图。

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

  此外,如果 map 数组满了,将申请一块更大的连续空间供 map 数组使用,将原有数据(指针)拷贝到新的数组中,然后释放旧的空间。

1.3 内部迭代器实现

   由上述可知,deque 底层将序列中的元素分别存储到了不同段的连续空间中,因此要想实现迭代器的功能,必须先解决如下 2 个问题:

  • 迭代器在遍历 deque 容器时,必须能够确认各个连续空间在 map 数组中的位置;

  • 迭代器在遍历某个缓冲区(连续的内存空间)时,需判断自己是否已经处于该缓冲区的边缘。如果是,则一旦前进或者后退,就需要跳跃到上一个或者下一个缓冲区中。因此,迭代器内部包含 4 个指针:

    cur			指向当前正在遍历的元素
    first 		指向当前 缓冲区 的首地址
    last		指向当前 缓冲区 的末尾地址
    node		指向 `map` 数组中存储的指向当前 缓冲区 的指针
    

在这里插入图片描述  如上述三点介绍的那样,这就是deque 的底层原理。


2. 构造函数

  deque构造函数有6种,其函数原型如下所示:

[1] explicit deque(const allocator_type& alloc = allocator_type());

[2] explicit deque(size_type n);
	         deque(size_type n, const value_type& val,
	                const allocator_type& alloc = allocator_type());
	                
[3] template <class InputIterator>
	 deque(InputIterator first, InputIterator last,
	       const allocator_type& alloc = allocator_type());
	       
[4] deque(const deque& x);
	deque(const deque& x, const allocator_type& alloc);
	
[5] deque(deque&& x);
	deque(deque&& x, const allocator_type& alloc);
	
[6]	deque(initializer_list<value_type> il,
          const allocator_type& alloc = allocator_type());

  其中:

  • [1] 创建一个空的容器,没有元素。
  • [2] 创建一个包含nval的容器。
  • [3] 通过两个迭代器对应的半开区间[first,last)创建容器,每个元素通过emplace构建,元素顺序与区间内顺序相同。
  • [4] 复制构造函数
  • [5] 移动构造函数
  • [6] 复制 initializer_list 对象中的元素创建一个容器,顺序与 il 相同。
    [注释]: initializer_list是C++11提供的新数据类型,和vector一样,initializer_list也是一种模板类型。可以使用.begin(), .end() 等方法。

   例: 代码中构造函数使用顺序与上述相同

int main ()
{
    unsigned int i;

    std::deque<int> first;                                  // [1]. empty deque of ints
    std::deque<int> second(4,100);                          // [2]. four ints with value 100
    std::deque<int> third(second.begin(),second.end());     // [3]. iterating through second

    std::deque<int> fourth(third);                          // [4]. a copy of third
    std::deque<int> fifth(std::move(third));                // [5]. a move of third
	
	int myints[] = {16,2,77,29};
  	std::deque<int> sixth(myints, myints + sizeof(myints) / sizeof(int) ); // [6]. with initializer_list

    std::cout << "The contents of sixth are:";
    for (std::deque<int>::iterator it = sixth.begin(); it!=sixth.end(); ++it)
        std::cout << ' ' << *it;

    std::cout << '\n';	// The contents of sixth are: 16 2 77 29

    return 0;
}

3. 常用函数

  • std::deque中成员函数如下图所示。
    member function

  • C++ vector总结中存在std::vector相同功能成员函数,此处便不在详细介绍,std::deque详情点击此处 c++plusplus

  • 此处简单叙述下各函数功能。

    assign			设置容器中元素
    at				通过下标随机访问,无效下标将抛出异常
    back			返回最后一个元素引用
    begin			返回正序迭代器,指向第一个元素
    cbegin			c++11新增,返回const的迭代器
    cend			c++11新增,返回const的迭代器
    clear			清空容器,size=0
    crbegin			c++11新增,返回const的迭代器
    crend			c++11新增,返回const的迭代器
    emplace 		移动语义,指定位置插入
    emplace_back 	移动语义,尾部位置插入
    emplace_front 	移动语义,头部位置插入
    empty			返回容器是否为空
    end				返回正序迭代器,指向最后一个元素后+1的位置
    erase			删除
    front			返回头元素引用
    insert			插入
    max_size		容器当前最大容量
    operator=		重载=
    operator[]		通过下标随机访问,无效下标将报错
    pop_back		尾部删除元素
    pop_front		头部删除元素
    push_back		尾部插入
    push_front		头部插入
    rbegin			返回一个逆序迭代器,它指向容器的最后一个元素
    rend			返回一个逆序迭代器,它指向容器c的第一个元素前面一个位置
    resize			重设容器大小
    size			返回容器元素个数
    swap			交换当前容器与参数容器中元素
     
    end...
    

参考链接:
[1] http://www.cplusplus.com/reference/deque/deque/
[2] https://blog.csdn.net/u012940886/article/details/80529721
[3] http://c.biancheng.net/view/6908.html

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值