C++ 《STL源码剖析》 deque 学习

Deque 简介

deque是“double—ended queue”的缩写,和vector一样都是STL的容器,deque 是双端数组,而 vector 是单端的。

deque 在接口上和 vector 非常相似,在许多操作的地方可以直接替换。

deque 可以随机存取元素(支持索引值直接存取,用[]操作符或at()方法,这个等下会详讲)。

deque 头部和尾部添加或移除元素都非常快速。但是在中部安插元素或移除元素比较费时。

使用时需要包含头文件 #include<deque> 。

Deque 实现原理

deque 的中控器

deque是连续空间(至少逻辑上看来如此),连续线性空间总令我们联想到array或vector。array无法成长,vector虽可成长,却只能向尾端成长,而且其所谓的成长原是个假象,事实上是(1)另觅更大空间;(2)将原数据复制过去;(3)释放原空间三部曲。如果不是vector每次配置新空间时都有留下一些余裕,其成长假象所带来的代价将是相当高昂。

deque系由一段一段的定量连续空间构成。一旦有必要在deque的前端或尾端增加新空间,便配置一段定量连续空间,串接在整个deque的头端或尾端。deque的最大任务,便是在这些分段的定量连续空间上,维护其整体连续的假象,并提供随机存取的接口。避开了“重新配置、复制、释放”的轮回,代价则是复杂的迭代器架构。

受到分段连续线性空间的字面影响,我们可能以为deque的实现复杂度和vector相比虽不中亦不远矣,其实不然。主要因为,既是分段连续线性空间,就必须有中央控制,而为了维持整体连续的假象,数据结构的设计及迭代器前进后退等操作都颇为繁琐。deque的实现代码分量远比vector或list都多得多。

deque采用一块所谓的map(注意,不是STL的map容器)作为主控。这里所谓map是一小块连续空间,其中每个元素(此处称为一个节点,node)都是指针,指向另一段(较大的)连续线性空间,称为缓冲区。缓冲区才是deque的储存空间主体。SGI STL 允许我们指定缓冲区大小,默认值0表示将使用512 bytes 缓冲区。

deque的整体架构如下图所示:

deque 的迭代器

让我们思考一下,deque的迭代器应该具备什么结构,首先,它必须能够指出分段连续空间(亦即缓冲区)在哪里,其次它必须能够判断自己是否已经处于其所在缓冲区的边缘,如果是,一旦前进或后退就必须跳跃至下一个或上一个缓冲区。为了能够正确跳跃,deque必须随时掌握管控中心(map)。所以在迭代器中需要定义:当前元素的指针,当前元素所在缓冲区的起始指针,当前元素所在缓冲区的尾指针,指向map中指向所在缓区地址的指针,分别为cur, first, last, node。

指针结构如下图所示:

deque的内部结构大致就是这样

下面简单介绍一下deque函数的删除我感觉挺有意思的

deque<T, Alloc, BufSize>::erase(iterator first, iterator last) {
  if (first == start && last == finish) {//如果是删全部
    clear();
    return finish;
  }
  else {
    difference_type n = last - first;//清除区间的长度
    difference_type elems_before = first - start;//清除区间前方的元素个数
    if (elems_before < (size() - n) / 2) {//前方元素比较少
      copy_backward(start, first, last);//向后移动
      iterator new_start = start + n;//新起点
      destroy(start, new_start);//删除冗余的元素
      for (map_pointer cur = start.node; cur < new_start.node; ++cur)
        data_allocator::deallocate(*cur, buffer_size());
      start = new_start;
    }
    else {
      copy(last, finish, first);
      iterator new_finish = finish - n;
      destroy(new_finish, finish);
      for (map_pointer cur = new_finish.node + 1; cur <= finish.node; ++cur)
        data_allocator::deallocate(*cur, buffer_size());
      finish = new_finish;
    }
    return start + elems_before;
  }
}

deque对于erase这个接口

它会根据具体未知来选择是往前移动还是往后移动

其他的函数 类似pop push其实和之前vector和list差不多

先判断空间够不够 是不是指向当前缓冲区的first|last 等一系列问题

如果空间不够 就申请新的缓冲区 然后map指针指向下一个map数组位置 然后 再对应指向新的缓冲区 顺便更新迭代器start end cur

原文地址:https://www.cnblogs.com/MengX/p/12336291.html

时间: 2024-10-09 06:06:50

C++ 《STL源码剖析》 deque 学习的相关文章

《STL源码剖析》学习之traits编程

侯捷老师在<STL源码剖析>中说到:了解traits编程技术,就像获得“芝麻开门”的口诀一样,从此得以一窥STL源码的奥秘.如此一说,其重要性就不言而喻了.      之前已经介绍过迭代器,知道了不同的数据结构都有自己专属的迭代器,不同的迭代器也有不同的特性,由于算法的接口是统一的,通过迭代器的不同属性,算法自动选择正确的执行流程,在完全任务的同时,也尽可能提高算法的执行效率.那算法如何获知迭代器的属性呢?这一光荣的任务就是traits完成的.在STL实现中,traits编程技术得到大量的运用

C++ 《STL源码剖析》学习-vector

本文章是笔者学习<STL源码剖析>的学习笔记,记录的是笔者的个人理解,因为个人的水平有限,难免会有理解不当的地方,而且该书出版的时间比较久,难免会有些不一样.如有不当,欢迎指出. vector是c++中经常用到的数据结构,而且在面试时也会有提及,因此了解vector很重要. 一说到vector,我们就很容易想到另外一个与它十分相似的数据结构,关于它们之间显著的差别,我觉得是在于空间运用的灵活性上.数组是静态的,在声明的时候就要指明其具体的空间大小,而vector是动态的,随着元素的增加,它内部

STL 源码剖析 deque实现源码

#ifndef _HJSTL_DEQUE_H_ #define _HJSTL_DEQUE_H_ /* * Author:hujian * Time:2016/4/28 * discription:this file is about deque structure. * */ #include "hjstl_alloc.h" #include "hjstl_construct.h" #include "hjstl_iterator.h" #inc

《STL源码剖析》学习笔记(二)

STL标准模板库作为C++标准库的一部分,其组件包括:容器.算法.迭代器.仿函数.配接器.配置器. 今天来说说容器,容器主要可以分为两种:序列式容器(元素是可序的,但并非有序).关联式容器. 一.序列式容器      1.vector 1)vector和C/C++的内置数组类似,只不过array空间是静态的,vector的空间则是可以改变的,当元素个数达到空间上限时,会重新分配空间,进行复制,然后删除原空间数据. 2)vector占用一段连续的存储空间,其内部含三个指针,分别指向:该连续空间的开

《STL源码剖析》学习笔记系列之七、八——仿函数和配接器

1. 仿函数 仿函数又名函数对象,具有函数性质的对象,就是传入一些参数,然后对参数进行某些运算,然后返回一个值.为了能够使行为类似函数,需要在类别定义中必须自定义function call 运算子operator(). 仿函数有如下几类:算术类仿函数(plus<T>.minus<T>)关系运算类仿函数(equal_to<T>.less<T>)逻辑运算类仿函数(logical_and<T>.logical_or<T>.logical_n

《STL源码剖析》学习笔记-第4章 序列式容器

1.vector 1.vector特性 (1)vector有自动扩容操作,每次扩容伴随着"配置新空间 / 移动旧数据 / 释放旧空间"的操作,因此有一定时间成本. (2)vector提供了reserve接口,如果能够对元素个数有大概了解,可以一开始就分配合适的空间. (3)vector的内存空间是连续的,对插入元素的操作而言,在vector尾部插入才是合适的选择.维护的是一个连续线性空间,所以vector支持随机存取. (4)vector动态增加大小时,并不是在原空间之后持续新空间(无

stl源码剖析 详细学习笔记 算法总览

//****************************基本算法***************************** /* stl算法总览,不在stl标准规格的sgi专属算法,都以 *加以标记 算法名称              算法用途         质变                   所在文件 accumulate          元素累计            否                   <stl_numeric.h> adjacent_differenc

stl源码剖析 详细学习笔记 算法(1)

//---------------------------15/03/27---------------------------- //算法 { /* 质变算法:会改变操作对象之值 所有的stl算法都作用在由迭代器[first,last)所标示出来的区间上.质变算法 就是 运算过程会更改区间内的元素内容 非质变算法:和质变算法相反 */ /* stl算法的一般形式 1>所有的泛型算法的前两个参数都是一对迭代器,通常称为first和last,用以标示算法的操作区间 2>stl习惯采用前闭后开区间

《STL源码剖析》学习笔记-第6章(一) set相关算法

STL中定义的set要求元素不得重复且已经排序.而set算法要求的都是有序区间(输出也是有序的),但元素可以重复出现. STL提供了4个set相关的算法,分别是并集(union).交集(intersection).差集(difference)和对称差集(symmetric difference),这4个算法接受的set必须是有序区间,都至少接受4个参数,分别表示两个set区间.一般而言,set算法前4个参数分别表示两个区间,第五个参数表示存放结果的区间的起始位置. 1.set_union 求两个

《STL源码剖析》学习笔记-第5章 关联式容器(二)

1.set和multiset set的特性: (1)所有元素都会根据元素的键值自动被排序. (2)set是集合,它的元素的键值就是实值,实值就是键值,不允许两个元素有相同的值. (3)不可以通过set的iterator来改变元素的值,因为set的元素值就是键值,改变键值会违反元素排列的规则. (4)在客户端对set进行插入或删除操作后,之前的迭代器依然有效.当然,被删除的元素的迭代器是个例外. (5)它的底层机制是RB-tree.几乎所有的操作都只是转调用RB-tree的操作行为而已. mult