第九章---顺序容器
这一章节实际上是讲了c++非常重要的一部分-----STL,现在只是学习最基本的容器的操作,今后还想学习源码剖析这本书。
1、顺序容器内的元素按位置进行存储和访问。元素的排列次序与元素值无关,而是由元素添加到容器的次序决定的,新的c++11标准库定义了六种顺序容器类型:vector,list,deque,forward_list,array(比内置数组更加的安全,快速),string(实际上它并不是顺序容器,只是它可以提供和顺序容器许多相关的操作,所以可以类似的理解成顺序),它们的差别在于访问元素的方式,以及添加或删除元素相关操作的运行代价。容器仅定义少量操作,大多数额外操作由算法库提供。在后面的泛型算法章节有更加详细的描述。
2、为了定义容器对象首先要包含相关头文件,如#include<vector>,#include<list>,#include<deque>,所有的容器都是类模板,必须为容器指定容器存放的元素类型进行实例化。所有的容器都提供了默认构造函数,除此之外还提供其他构造函数。如下:
1:C<T> c;默认构造函数。
2:C c(c2);复制构造。
3:C c(b,e);用b,e标示的范围创建c,b、e为迭代器。
4:C c(n,t)用n个t的元素创建c。5:C c(n)。创建有n个元素的c。调用默认构造函数。
将一个容器复制给另一个容器时,容器类型和元素类型都必须匹配。vector<int> ivec;vector<int>ivec2(ivec);系统允许通过传递一对迭代器,将一个容器的一部分元素赋值给另一个容器。迭代器指向要复制的第一个元素和最后一个元素的下一位置。
容器元素必须满足一下两个条件:
1:元素类型必须支持赋值运算。
2:元素类型对象必须可以复制。
引用类型因为它不支持一般意义上的赋值运算(从一而终,)IO库类型和auto_ptr类型均不能作为容器元素类型,原因与引用类似。
3、详细介绍各容器
vector :
vector和built-in数组类似,是一个在堆上建立的一维数组,它拥有一段连续的内存空间,并且起始地址不变,因此它能非常好的支持随即存取,即[]操作符。vector因为存储在堆上,所以支持erase(), resieze()(重新划分容器容量)等操作; vector不用担心越界当空间不够用的时候,系统会自动按照一定的比例(对capacity( )大小)进行扩充。在vector序列末尾添加(push_back( ))或者删除(pop_back( ))对象效率高,在中间进行插入或删除效率很低,主要是要进行元素的移动和内存的拷贝,原因就在于当内存不够用的时候要执行重新分配内存,拷贝对象到新存储区,销毁old对象,释放内存等操作,如果对象很多的话,这种操作代价是相当高的。为了减少这种代价,使用vector最理想的情况就是事先知道所要装入的对象数目,用成员函式 reserve( ) 预定下来;vector最大的优点莫过于是检索(用operator[ ])速度在容器中是最快的。
list :
list的本质是一个双向链表(根据sgistl源代码),内存空间不连续,通过指针进行操作。说道链表,它的高效率首先表现是插入,删除元素,进行排序等等需要移动大量元素的操作。显然链表没有检索操作operator[ ], 也就是说不能对链表进行随机访问,而只能从头至尾地遍历,这是它的一个缺陷。list有不同于前两者的某些成员方法,如合并list的方法splice( ), 排序sort( ),交换list 的方法swap( )等等。
deque :
deque是一个double-ended。queue是由多个连续内存块构成,deque是list和vector的兼容,分为多个块,每一个块大小是512字节,块通过map块管理,map块里保存每个块得首地址。因此该容器也有索引操作operator[ ],效率没vector高。另外,deque比vector多了push_front( ) & pop_front( )操作。在两端进行此操作时与list的效率 差不多。
Forward list:
前向链表是序列容器,插入和擦除操作序列内的任何地方。前向链表的实现方式和单链表相同,在序列中顺序保存每个元素指向下一个元素的关联。forward_list容器与list容器的主要设计区别是list保持内部唯一的一个链接到下一个元素,而后者则保持每个元素的两个链接:一个指向下一个元素和一个前一个。list允许高效在两个方向迭代,但每个元素的消耗额外的存储空间,并轻微较高的时间开销插入和删除元素的迭代。forward_list对象只能向前遍历。与其他的基本标准序列容器(array,vector和deque)相比,forward_list一般在容器内的任何位置中的元素的插入、提取和移动操作效率更高,因此在算法中较密集的使用这些操作,例如排序算法。相比其他序列容器,forward_lists的主要缺点是缺乏直接访问他们的位置的元素,例如,要进入第六个元素在forward_list的一个遍历从一开始就到那个位置,这需要线性时间之间的距离。
std::array
array是一个支持随机访问且大小(size)固定的容器(译注:可以认为是一个紧缩版的vector吧)。它有如下特点:
1.不预留多余空间,只分配必须空间(译注:size() == capacity())。2.可以使用初始化表(initializer list)的方式进行初始化。
3.保存了自己的size信息。4.不支持隐式指针类型转换。换句话说,可以认为它是一个很不错的内建数组类型,但是和内置数组不是一同一个东西。
4、各容器常见操作
4.1添加元素
有三类函数push_back()、push_front()、insert(),用insert()在指定位置插入单个元素时,返回指向新元素的迭代器,其他的都返回void
4.2容器大小操作
size(), max_size(), empty() resize()。resize()能删除多出来的元素。
4.3访问元素
用迭代器迭代容器或者使用下标操作(list不支持下标操作)
4.4删除元素
erase()(返回指向删除元素后的迭代器), clear(), pop_back(), pop_front() (pop_操作只删除元素,不返回删除的元素值,返回void)
assign赋值操作 , swap 交换容器操作(不会破坏迭代器)
5、容器适配器
顺序容器还有三种适配器,主要作用是包装其它容器使之具有某种操作特征。
stack 堆栈适配器 ( 可用的容器类型 vector deque list)
queue 队列适配器 ( 可用的容器类型 deque list)
priority_queue 优先级队列 (可用的容器类型 deque vector)
6、选择准则