顺序容器(sequentialcontainer)
1. 简介
1.1定义:
将单一类型元素聚集起来成为容器,然后根据位置来存储和访问这些元素,这就是顺序容器。
标准库定义了三种顺序容器:
1. vector #include<vector>
2. list #include<list>
3. deque #include<deque>
顺序容器适配器adaptor
1. stack
2. queue
3. priority_queue
1.2 容器定义的类型别名
Size_type 无符号整型,足以存储此容器类型的最大可能容器长度
Iterator 此容器类型的迭代器类型
Const_iterator 元素的只读迭代器类型
Reverse_iterator 按逆序寻址元素的迭代器
Const_reverse_iterator 元素的只读逆序迭代器
Difference_type 足够存储两个迭代器差值的有符号整型,可为负数
Value_type 元素类型
Reference 元素的左值类型,是value_type&的同义词
Const_reference 元素的常量左值类型,等效于constvalue_type&
2. 容器初始化
C<T> c; 创建一个名为c的空容器。C是容器类型名,如vector,T是元素类型,如int或string。适用于所有容器。
C c(c2) 创建容器c2的副本c;c和c2必须具有相同的容器类型,并存放相同类型的元素,适用于所有容器。
C c(b, e) 创建c,其元素是迭代器b和e标识的范围内元素的副本。适用于所有容器。
C c(n, t) 用n个值为t的元素创建容器c,其中值t必须是容器类型C的元素类型的值,或者是可转换为该类型的值。只适用于顺序容器。
C c(n) 创建有n个值初始化元素的容器c。只适用于顺序容器。
3. 顺序容器的操作
3.1 增加元素
c.push_back(t) 尾部插入元素,容器长度+1。三种容器均适用
c.push_front(t) 前端插入元素,容器长度+1。只适用于list和deque
插入操作insert() 一般有三种版本:
c.insert(p, t) 在迭代器p所指向元素的前面插入t元素,返回指向新添加元素的迭代器
c.insert(p, n, t) 在迭代器p所指向元素的前面插入n个值为t的元素,返回void类型
c.insert(p, b, e) 在迭代器p所指向元素的前面插入迭代器b和e标记的范围内的元素,返回void类型
3.2 设置容器大小
c.size() 返回容器c中的元素个数。返回类型为c::size_type
c.max_size() 返回容器c中可容纳的最多元素个数,返回类型为c::size_type
c.empty() 返回标记容器的大小是否为0,返回值类型为bool
调整容器长度大小resize()有两个版本:
c.resize(n) 调整容器c的长度大小,使其能够容纳n个元素,如果n<c.size(),则删除多出来的元素;否则,添加采用值初始化的新元素。
c.resize(n, t) 调整容器c的大小,使其能容纳n个元素。所有新添加的元素值都是t。
3.3 访问元素
c.back() 返回容器c的最后一个元素的引用。如果c为空,则该操作未定义
c.front() 返回容器c的第一个元素的引用,如果c为空,则该操作未定义
c[n] 返回下标为n的元素的引用,如果n<0或者n>=c.size(),则该操作未定义, 只是用于vector和deque容器。
c.at(n) 返回下标为n的元素的引用,如果下标越界,则操作未定义,
只适用于vector和deque容器
3.4 删除元素
c.erase(p) 删除迭代器p所指向的元素
返回一个迭代器,它指向被删除元素后面的元素。如果p指向容器内的最后一个元素,则返回的迭代器指向容器的超出末端的下一位置。如果p本身就指向超出末端的下一位置的迭代器,则该函数未定义。
c.erase(b, e) 删除迭代器b和e所标记的范围内所有的元素
返回一个迭代器,它指向被删除元素段后面的元素。如果e本身就是指向超出末端的下一位置的迭代器,则返回的迭代器也指向容器的超出末端的下一位置。
c.clear() 删除容器c内的所有元素,返回void
c.pop_back() 删除容器c的最后一个元素,返回void。如果c为空容器,则该函数未定义。
c.pop_front() 删除容器c的第一个元素,返回void。如果c为空容器,则该函数未定义
是适用于list或deque容器。
3.5 赋值与swap
c1 = c2 删除容器c1的所有元素,然后将c2的元素复制给c1。c1和c2的类型(包括容器类型和元素类型)必须相同。
c1.swap(c2) 交换内容:调用完该函数后,c1中存放的是c2原来的数据,c2中存放的则是c1原来的元素。c1和c2的类型必须相同。该函数的执行速度通常要比将c2的元素复制到c1的操作快。
c.assign(b, e) 重新设置c的元素:将迭代器b和e标记的范围内所有的元素复制到c中。b和e必须不是指向c中元素的迭代器。
c.assign(n, t) 将容器c重新设置为存储n个值为t的元素。
3.6 vector容器的自增长
引言: vector容器的元素以连续的方式存放----每一个元素都紧挨前一个元素存储。
情景: 添加新元素的时候,如果没地方放新元素了,就需要重新分配内存空间,用来存放原来的元素以及新添加的元素:
存放在旧存储空间中的元素被复制到新的存储空间里,接着插入新元素,最后撤销旧的存储空间。
实际: 为了使vector容器实现快速的内存分配,其实际分配的容量要比当前所需的空间多一些。
两个操作:
v.capacity() 获取在容器需要分配更多的存储空间之前能够存储的元素总数。
区别于v.size(),v.size()是当前有的元素的总数,v.capacity()是能够存储的元素总数,一般v.size()<=v.capacity()
v.reserve() 告诉vector容器应该预留多少个元素的存储空间。
注意: 每当vector容器不得不分配新的存储空间时,以加倍当前容量的分配策略实现重新分配。
4. 知识扩展
4.1 容器的选用
容器是否连续存储会显著的影响:
1. 在容器的中间位置添加或删除元素的代价;
2. 执行容器元素的随机访问代价;
分类:
连续存储的容器: vector 、 deque 快速随机访问/插入删除开销大
非连续存储的容器: list 快速插入删除/随机访问开销大
原因:
vector 的每一次随机访问都是距离其起点的固定偏移,因此随机访问非常有效率
list随机访问需要通过顺序跟随指针来遍历所有的元素,所以效率低
vector的每一次插入删除操作,都要将该位置后面的所有元素移动位置,开销大,效率低。
list可以随意地插入和删除容器内的元素,而不必移动其它的元素,所以开销小,效率高。
4.2 string类型具有容器的特性
String 类型支持许多类似于vector容器的操作。具体操作可以查阅。
4.3 容器适配器
本质上,适配器是使一事物的行为类似于另一事物的行为的一种机制。容器适配器让一种已存在的容器类型采用另一种不同的抽象类型的工作方式实现。
顺序容器适配器adaptor: 可以建立在某种容器之上
stack: vector、list、deque
queue : list
priority_queue: vector、deque
栈适配器
支持的操作:
s.empty() 如果栈为空,则返回true,否则返回false
s.size() 返回栈中元素的个数
s.pop() 删除栈顶元素,则不返回其值
s.top() 返回栈顶元素的值,但不删除该元素
s.push(item) 在栈顶压入新元素
队列和优先级队列支持的操作:
q.empty() 如果队列为空,则返回true,否则返回false
q.size() 返回队列中元素的个数
q.pop() 删除队首元素,但不返回其值
q.front() 返回队首元素的值,但不删除该元素,
(该操作只适用于队列)
q.back() 返回队尾元素的值,但不删除该元素
(该操作只适用于队列)
q.top() 返回具有最高优先级的元素值,但不删除该元素(该操作只适用于优先级队列)
q.push(item) 对于queue,在队尾压入一个新元素,对于priority_queue,在基于优先级的适当位置插入新元素