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

1.vector

vector的数据安排以及操作方式与array非常相似,两者的唯一差别在于空间的运用的灵活性。array是静态空间,一旦配置了就不能再改变。vector是动态空间,随着元素的加入它的内部机制会自行扩充空间以容纳新元素。

(1)vector的迭代器

因为vector维护的是一个连续线性空间,所以无论其元素型别为何,普通指针都可以作为vector的迭代器。因为vector迭代器所执行的操作行为,如operator*,operator->,operator++,operator--,operator+,operator-,operator+=,operator-=,普通指针天生就具备。可见,vector提供的是Random
Access Iterator。

vector的迭代器定义如下:

(2)vector的数据结构

vector所采用的数据结构非常简单:线性空间。它采用两个迭代器start和finish分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器end_of_storage指向整块连续空间的尾端:

为了降低空间配置时的速度成本,vector实际配置的大小可能比目前vector存储的数据所需的空间要大,以备将来的扩充。也就是说,一个vector的容量永远大于或等于其大小。vector的空间使用情况如下:

注意,所谓动态增长,并不是在原来空间之后接续新空间,而是以原大小的两倍配置一块较大空间,然后将原内容拷贝过来。因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了。

(3)vector的元素操作

a.push_back():若还有剩余空间,直接使用剩余空间。若没有剩余空间了,则开辟一块新的更大的空间,将vector存储的所有内容复执过来,再将新元素插入。

b.pop_back():将尾端元素销毁掉,再调制尾端的位置。

c.erase(first,last):将last到finish的元素复制到first起始的内存地址处,如下图:

d.insert(position,n,x):分三种情况来操作:(1)备用空间大于等于新增元素个数,插入点之后的元素个数大于新增元素个数。(2)备用空间大于等于新增元素个数,插入点之后的元素个数小于等于新增元素个数。(3)备用空间小于新增元素个数。三种情况对应的操作如下:

2.list

相较于vector的连续线性空间,list就显得复杂许多,它的好处是每次插入或者删除一个元素,就申请或释放一个元素空间。因此,list对于空间的运用绝对的精确,一点也不浪费。而且,对于任何位置的元素插入或元素移除,list永远是常数时间。

(1)list的节点

STL list的节点结构如下,它是一个双向节点结构:

(2)list的迭代器

list不再像vector一样以普通指针作为迭代器,因为其节点不保证在存储空间中连续存在。list迭代器必须有能力指向list的节点,并能进行正确的递增、递减、取值、成员存取等操作,如下图所示:

迭代器的设计如下所示:

(3)list的数据结构

list不仅是一个双向链表,而且还是一个环状双向链表,所以它只需要一个指针,便可以完整表现整个链表:

一个list的示意图如下:

(4)list的操作

对STL list的操作就是对一个双向循环链表的操作。下面以transfer为例说明:

时间: 2024-10-07 14:58:45

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

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

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

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源码剖析》读书笔记之序列式容器(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把数据源中的数据