顺序容器简介:
STL的六大组成部分之一的容器分为两类,一类是顺序容器,一类是关联容器,本章主要介绍顺序容器,以及它们的特点
顺序容器主要类型有 vector,string,deque,list,forward_list,array
vector: 可变大小数组,支持快速随机访问,在尾部之外的位置插入或删除元素可能很慢
C++语言既有类模板,也有函数模板,其中,vector就是一个类模板。
举例:
vector<int> ivec;//ivec保存int类型的对象
vector<vector<string>> lines; //vector的vector,此处lines是一个vector,其元素类型是string的vector
vector是模板而非类型,由vector生成的类型必须包含vector中元素的类型,例如vector<int>
vector能容纳绝大多数的类型的对象作为元素,但是不能包含引用,因为引用不是对象
可以默认初始化vector对象,从而创建一个指定类型的空vector,程序在运行时可以很高效的往vector对象中添加元素
deque: 双端队列,支持快速随机访问。在头尾位置插入/删除速度很快
举例:
deque<int> data;
list: 双向链表,只支持双向顺序访问,不支持随机访问,在list中任何位置进行插入/删除操作速度都很快
forward_list: 单向链表。只支持单向顺序访问。在链表任何位置进行插入/删除操作速度都很快
array: 固定大小数组,支持快速随机访问,不能添加或删除元素
string: 与vector相似的容器,但专门用于保存字符,随机访问快,在尾部插入/删除速度快
除了固定大小的array之外,其他容器都提供高效,灵活的内存管理。我们可以添加和删除元素,扩张和收缩容器的大小。
容器保存元素的策略对容器操作的效率有着固有的,有时是重大的影响。在某些情况下,存储策略还会影响特定容器是否支持特定操作。
例如:string和vector将元素保存在连续的内存空间中。由于元素是连续存储的,由元素的下标来计算其地址是非常快速的。
但是在这两种容器的中间位置添加或删除元素就会非常耗时:在一次插入或删除操作后,需要移动插入/删除位置之后的所有元素,来保持连续存储。
而且添加一个元素有时可能还需要分配额外的存储空间。在这种情况下,每个元素都必须移动到新的存储空间中
list和forward_list两个容器的设计目的是令容器任何位置的添加和删除操作都很快速。
作为代价,这两个容器不支持元素的随机访问:为了访问这一个元素,我们只能遍历整个容器。
而且与vector,deque和array相比,这两个容器的额外内存开销也很大。
deque是一个更为复杂的数据结构,与string和vector类似,deque支持快速的随机访问。
与string和vector一样,在deque的中间位置添加或删除元素的代价可能很高。
但是,在deque的两端添加或删除元素都是很快的,与list或forward_list添加删除元素的速度相当。
forward_list和array是新C++标准增加的类型。与内置数组相比,array是一种更安全,更容易使用的数组类型。
与内置数组类似,array对象的大小是固定的。因此array不支持添加和删除元素以及改变容器大小的操作。
forward_list的设计目标是达到与最好的手写的单向链表数据结构相当的性能。
因此forward_list没有size操作,因为保存或计算其大小就会比手写链表多出额外的开销。
对其他容器而言,size保证是一个快速的常量时间的操作
确定使用哪种顺序容器
通常,使用vector是最好的选择,除非你有很好的理由选择其他容器。
以下是选择容器的基本原则:
- 除非你有很好的理由选择其他容器,否则应该使用vector。
- 除非你的程序有很多小的元素,且空间的额外开销很重要,则不要使用list或forward_list
- 如果程序要求随机访问元素,应使用vector或deque
- 如果程序要求在容器的中间插入或删除元素,应使用list或forward_list
- 如果程序需要在头尾位置插入或删除元素,但不会在中间位置进行插入或删除元素,则使用deque