C++ 练习中使用的库和工具 - vector 和 deque
向量库 - vector
标准库类型 vector 提供类似传统 c 语言中的数组的功能,表示同类型元素的集合.用户可通过头文件 vector 对其进行使用.
#include<vector> using std::vector; //对 vector 的命名空间声明
标准库中定义的 vector 为一个类模版,用户在使用时根据 vector 需要存储的数据类型进行实例化,如存储 int 类型的 vector,则其对应的类为 vector<int>. vector 中存储的数据的类型既可以是如 int/float 等基本数据类型,也可以是类类型如 string/vector 等.若包含数据对象的类型为 content_type,则其实例化的类为 vector<content_type> .下面以存储数据类型为 int 类型为例,列举了 vector 常用的定义方式.
vector<int> a; //定义了一个空的 vector<int> 类 a vector<int> b( a ); //使用类 a 来初始化 b,需保证类型均为 vector<int> vector<int> b = a; //同上,拷贝初始化 vector<int> b( n, num ); //定义一个包含有 n 个元素的类 b,每个元素均为 num vector<int> b( n ); //同上,b 包含有 n 个元素,元素执行值初始化(内置类型为0,类类型执行默认初始化)
注意,在实例化 vector 类型的 vector 时,如 vector< vector<int> >,老版本的编译器需保证 '>' 与 '>' 之间使用空格隔开,否则会被解析为流输出运算 ">>".新版本的编译器则不必使用空格.
与传统 c 中数组不同的是, vector<type> 对象在创建后,其大小是可变的,这里的大小指 vector 中存储的元素的数量.不论 vector<type> 对象在定义时为空(默认初始化)或包含若干个元素(上述第4和第5种初始化方式),使用者均可对其进行添加元素的操作.事实上,vector 被要求能够在运行时高效快速的添加元素,故而除了某些情况( 如所有元素均一样,使用拷贝初始化 )外,开始的时候创建空的 vector 对象,再动态向其中添加元素的方式可能更高效.
添加数据方式
通过 push_back 方法在 vector< type > a 存储的数据尾部添加数据, push_back 方法使用待添加的数据作为参数.以下以 vector<int> 为例进行说明.
a.push_back( i ) //在 vector a 的尾端添加一个元素 i,其中 i 需保证与 a 定义时的实例化的类型一致(或可进行转换)
通过 insert 方法在 vector< type > a 中指定的位置处插入数据, insert 方法第一个参数为迭代器指定的插入位置,第二个参数为待插入的数据.迭代器在这里不做介绍,只需要清楚 a.begin() 返回一个指向 a 中第一个元素位置的迭代器, a.begin() + n 代表指向 a 中第 n 个元素位置的迭代器.( 注意不能使用超出 a 中已有元素位置的迭代器位置 ).
a.insert( a.begin() + k, i ) //将元素 i 插入到 a 中的第 k 个元素位置
( insert 操作后所有与该 vector<type> 相关的迭代器均失效. )
在具体实现上, vector 保证在尾端添加元素的操作是高效的,但是插入操作则会影响效率( vector 中所有元素以连续方式进行存储 ).
删除数据方式.
删除数据方式与添加数据方式相对应,通过 pop_back 方法去除 vector 尾部的数据,通过 erase 方法删除 vector 指定位置处的数据,通过 clear 方法去除 vector 中所有元素.( erase 方法使用后,所有指向被删除元素后的迭代器均失效 )
a.pop_back() //去除 a 中最后一个元素 a.erase( a.begin() + k ) //去除 a 中第 k 个位置的元素 a.erase( a.begin(), a.begin() + k ) //去除 a 中 [ 0 , k ) 间的元素 a.clear() //去除 a 中所有元素
可通过 resize 方法改变 vector 中元素的数量.其包含有两种形式,单参数调用时,其接受一个长度参数 n ,表示将 vector<type> a 中的元素扩充或减少到 n 个.使用两个参数时,其第一个参数为长度 n,第二个参数 val 表示填充时使用的数据,若 resize 使原 vector 扩充,则扩充的元素使用 val,若 resize 使原 vector 中元素减少,则第二个参数被忽略.
vector<int> a; //默认初始化一个空的 vector<int> 对象 a a.resize( 5 ); //使得 a 中元素数量变为 5 个,扩充使用值初始化( 这里使用 0 ),减少则直接去除尾部元素 a,resize( 7, 4 ); //扩充 a 中元素数量至 7 个,使用 7 填充新增的两个元素,已有元素不改变
其他 vector 支持的操作
a.empty() //若 a 中无元素,则返回 true a.size() //返回 a 中已存储元素的个数 a[ n ] //索引访问 a 中位置 n 上的元素( 返回引用 ),索引从 0 开始,引用意味着可通过 a[ n ] = i 的方式对 a 中第 n 个元素进行修改( 索引范围不超过 a.size() ) a.at( n ) //索引访问,[ ] 不会进行越界检查,而 at 函数越界会抛出异常 a.back() //返回 a 中最后一个元素的引用 a.front() //返回 a 中第一个元素的引用
双端队列 - deque
vector 可以满足程序基本的数据存取的需求,但其仅可单方向(总是从尾端)进行数据的增长和删除,而 deque( double-ended queue )则支持在存储数据的头部和尾部进行数据的增长和删除.一个使用建议是,在默认情况下,使用 vector 存储数据,而当大部分的数据处理过程发生在数据头部和尾部时,使用deque.
deque 支持上文中介绍到的 vector 支持的操作,包括对元素的添加/删除/访问等.其与 vector 最大的两个区别在于, 第一,deque 支持通过 push_front 和 pop_front 在存储数据的头部进行数据的访问和存储.第二,vector 通过线性方式( 所有数据连续 )存储数据,而 deque 则是分段处理数据,故而在使用时 vector 效率更高( 得益于其限制只能在尾端进行数据增长 ).
a.push_front( i ) //在存储数据的头部添加元素 a.pop_front() //删除存储数据头部的第一个元素
参考
cs106L course reader Chapter 5 STL Sequences Containers
C++ Primer P86-91