《STL源码解析》读书笔记之序列式容器(2)

1.deque

deque和vector的最大差异在于deque允许在常数时间内对首端进行元素的插入和删除操作。而且deque没有容量的观念,因为它是动态地以分段连续空间组合而成的,随时可以增加一段新的空间并链接起来。像vector那样因旧空间不足而重新配置一块更大空间的情况在deque里是不会发生的。虽然deque也提供Random Access Iterator,但它的迭代器并不是普通指针,这影响了很多操作的效率。

(1)deque的map

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

deque采用一块所谓的map作为主控。这里所谓map是一小块连续空间。其中每一个元素都是指针,指向另一段较大的连续空间,称为缓冲区。缓冲区才是deque的存储主体。STL允许我们指定缓冲区大小,如果不指定则默认使用512bytes缓冲区。

deque的定义:

deque里面定义的map对象其实是一个T**,也就是说它是一个指针,所指之物又是一个指针,指向型别为T的一块空间,如下图所示:

(2)deque的迭代器

deque是分段连续空间。维持其“整体连续”假象的任务,落在了迭代器的operator++和operator--两个运算子身上。deque迭代器的数据结构设计如下:

deque的map,缓冲区,迭代器的互相关系如下:

假设现在有一个deque<int>,并令其缓冲区大小为32。经某些操作后deque拥有20个元素。每个int占4字节空间,则每个缓冲区可以存8个int。20个int将占用3个缓冲区,其中第三个缓存区将还剩余16bytes的剩余空间。此时deque的内存使用情况如下:

由于deque特殊的内存结构,当进行指针操作,遇到缓冲区边缘时,要特别注意,有的时候可能需要跳到另外一个缓冲区(实现参考《STL源码解析》148页)。

(3)deque的数据结构

deque除了维护一个先前说过的map的指针外,也维护start,finish两个迭代器,分别指向第一个缓冲区的第一个元素和最后一个缓存区的最后一个元素。此外,它也应该记住当前map的大小。因为map所提供的节点不足,就必须重新配置更大的一块map。

2.stack

stack是一种先进后出的数据结构。它只有一个出口。stack允许新增元素,移除元素,取得顶端元素。但除了顶端外,没有其他任何方法可以存取stack的其它元素。

deque是双向开口的数据结构,以deque为底部结构并封闭其头端开口,便可形成一个stack。

stack是以deque为底部容器完成其所有工作,像stack这种“修改某物接口,形成另一种风貌”的类被称为adapter。其源代码如下:

时间: 2024-10-12 05:10:34

《STL源码解析》读书笔记之序列式容器(2)的相关文章

STL 源码剖析读书笔记三:序列式容器之 vector、list

1. STL 中的容器 容器,置物之所也.STL 容器即是将运用最广的一些数据结构实现出来.如下图所示: 上图以内缩方式来表达基层和衍生层的关系.所谓衍生,并非派生关系,而是内含关系.例如 heap 内含一个 vector,priority-queue 内含一个 heap.stack.queue都内含一个 deque,set/map/multimap/multiset 都内含一个 RB-tree,hash_x 都内含一个 hashtable. 2. 序列式容器之 vector 所谓序列式容器,其

STL 源码剖析读书笔记四:序列式容器之 deque、stack、queue

1. 序列式容器 deque 1.1 deque 概述 vector是单向开口的连续线性空间,用户只能在vector尾部进行插入删除操作,而 deque 是一种双向开口的连续线性空间,允许我们在头尾两端操作. deque 和 vector 的最大差异在于: deque 允许常数时间对头端元素进行插入和移除操作 deque 没有所谓容量(capacity)概念,因为它是动态地以分段连续的空间组合而成,随时可以增加一段新的空间并链接起来 deque提供的迭代器也是 RandomAccess Iter

STL 源码剖析读书笔记一:空间配置器

1. STL 的空间配置器 STL 空间配置器在运用的角度来说,是最不需要介绍的,它总是隐藏在一切组件背后.但若以 STL 的实现角度而言,第一个需要理解的就是空间配置器. 根据 STL 规范,以下是 allocator 的必要接口: allocator::value_type allocator::pointer allocator::const_pointer allocator::reference allocator::const_reference allocator::size_ty

《STL源码解析》读书笔记之序列式容器(1)

1.vector vector的数据安排以及操作方式与array非常相似,两者的唯一差别在于空间的运用的灵活性.array是静态空间,一旦配置了就不能再改变.vector是动态空间,随着元素的加入它的内部机制会自行扩充空间以容纳新元素. (1)vector的迭代器 因为vector维护的是一个连续线性空间,所以无论其元素型别为何,普通指针都可以作为vector的迭代器.因为vector迭代器所执行的操作行为,如operator*,operator->,operator++,operator--,

《STL源码剖析》读书笔记之序列式容器(3)

1.heap heap不属于STL容器组件,它是priority queue的底层实现机制. (1)push_heap算法 向堆中加入元素,首先将要加入的元素放到堆所在数组的末端,然后再对这个元素进行上溯操作,直到新堆合法为止.如下图所示: (2)pop_heap算法 pop_heap操作取走堆中的最大(小)值.根据堆的特性,堆的最大(小)值必定是堆所存数组的第一个元素.取堆的最大(小)元素时,将堆的最后一个元素和堆的第一个元素互换,然后再对第一个元素进行下溯操作,直到新堆满足堆的定义.下图给出

Stl源码剖析读书笔记之Alloc细节

阅读基础: Foo *pf = new Foo; 执行了两个步骤: 1)::operator new 向系统申请内存. 2) 调用Foo::Foo()构造函数构造实例.  ==> 申请内存,构造实例. delete pf; delete; 执行了两个步骤: 1)调用Foo::~Foo()析构函数. 2). ::operator delete释放内存.         ==> 析构实例,释放内存. Stl Alloc实现: Stl为了高效利用内存,将这两部分分开,分成了四个操作( 构造::con

STL 源码剖析读书笔记二:迭代器与traits

1. 迭代器概述 迭代器是一种抽象的设计概念,现实程序语言中并没有直接对应这个概念的实物.<设计模式>中对于迭代器模式的定义为:提供一种方法,使之能够依序访问某个聚合物所含的各个元素,而又无需暴露该聚合物的内部表述方式. STL 的中心思想在于:将数据容器和算法分开,彼此独立设计,再以迭代器粘合.容器和算法的泛型化在技术角度来看并不困难,C++ 的类模板和函数模板可分别达成目标.如何设计出两者的良好粘合剂,才是大难题. 迭代器是一种类似于指针的对象,而指针的各种行为中最常见也最重要的便是内容提

STL 源码解析

一开始一直无法理解STL中的内存分析,一天很困,翻开了侯捷的STL源码解析,阅读一二,这是一针见血,字字珠玑,解开了一个又一个迷惑~ 简单记录,和大家分享一下 1) 空间适配器 template <class T1,class T2> inline void _construct(T1 *p,const T2 &value) { new (p) T1(value);  // placement new, and allocate object on the requested memo

2015.07.20MapReducer源码解析(笔记)

MapReducer源码解析(笔记) ? 第一步,读取数据源,将每一行内容解析成一个个键值对,每个键值对供map函数定义一次,数据源由FileInputFormat:指定的,程序就能从地址读取记录,读取的记录每一行内容是如何转换成一个个键值对?Mapper函数是如何调用键值对?这是由InputFormatClass完成的,它在我们的例子中的具体实现类是TextInputFormat(Text是普通的文本,log日志,数据库中的数据就不是),总的来说:TextInputFormat把数据源中的数据