c++ vector概念和相关操作
最近开始系统学习c++标准库,以及练习写博客。先从翻译STL文档开始,加入了自己的一点理解,大概会有一些错误,日后逐渐修正。
概念
vector是盛放序列的容器,是一种尺寸可变的数组。像数组一样,vector使用连续的内存空间来存放元素,这意味着可以使用平常的指针偏置来读取元素,能像数组一样高效。但不同于数组的是,vector可以动态改变大小。
在内部,vector使用一个动态分配的数组来存储元素,当数组已满且需要插入新元素时,vector会重新分配一个新的更大空间的数组,将原来的元素拷贝过去并将原来的数组内存空间回收。这样时间上的成本会相对较高,不过vector也因此不需要每加入一个元素就调整大小。
capacity意为容量,是可以用来装元素的空间;size意为尺寸,是现有元素占的空间。相应的,vector可以主动的扩大自己的容量来提前准备可能的尺寸的增加,因此通常vector的容量是大于尺寸的,前文的“大小”一词即指容量。标准库有很多的策略来平衡内存使用和重分配,但是在任何情况下重分配只会发生在内部空间的对数级增长上,因此,向vector的末尾添加单个元素时的时间成本为O(1)。
因此,相比于数组,vector会消耗更多的内存为了更高效的管理和增长存储容量。
与其他序列容器相比(比如队列、链表、单向链表等)vector在读取元素上是十分高效的(就像数组一样),而且相对来讲在末尾增减元素时也比较高效,不过在其他位置增减元素时就稍逊一筹了,而且迭代器和引用的一致性也要稍弱于链表和单链表。
成员函数
- 构造函数
(1) explicit vector(const allocator_type& alloc = allocator_type());
用法:vector<int> v; // 声明一个空的vector
(2) explicit vector(size_type n);
explicit vector(size_type n, const value_type& val, const allocator_type& alloc = allocator_type());
用法:vector<int> v(10); // 声明一个容量、尺寸都为10的vector
vector<int> v(10, 1); // 声明一个容量、尺寸都为10的vector,元素的初始值为1
(3) template <InputIterator>
vector(InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type());
用法: vector<int> a(10, 1); vector<int> b(a.begin(), a.end());
int a[] {1, 2, 3}; vector<int> b(a, a + 3);
/* 可用其他可以用迭代器读取元素的容器(vector、数组)初始化vector */
(4) 复制构造函数
vector(const vector& x);
vector(const vector& x, const allocator_type& alloc = allocator_type());
用法: vector<int> a(5, 2); vector<int> b(a);
(5) 移动构造函数
vector(vector&& x);
vector(vector&& x, const allocator_type& type);
(6) vector(initialize_list<value_type> il, const allocator_type& alloc = allocator_type());
- 迭代器
begin() // 指向第一个元素的迭代器
end() // 指向最后一个元素后面位置的迭代器
rbegin() // 指向最后一个元素的反向迭代器
rend() // 指向第一个元素前面的位置的反向迭代器
cbegin()
cend()
crbegin()
crend()
- 与容量有关的
size() // 尺寸,vector已有的元素个数
max_size() // vector可容纳元素的最大数量,与系统有关
resize(n) // 调整vector的尺寸,若变大,则0填充,若变小则裁减
capacity() // 容量,vector当前可容纳的最多元素数目
empty() // 测试vector是否为空
reserve(n) // 改变容量
shrink_to_fit() // 使容量capacity等于尺寸size
- 读取元素
operator[] // v[2]
at // v.at(3)
front() // 第一个元素
back() // 最后一个元素
data() // 指向第一个元素的指针,若vector为空则返回空指针
- 元素操作
(1) 赋值
template <typename InputIterator>
void assign(InputIterator first, InputIterator last);
void assign(size_type n, const value_type& type);
void assign(initializer_list<value_type> il);
用法:与构造函数相同,使用assign后vector不会保留以前的值
(2) 添加元素
末尾插入
void push_back(const value_type& val);
void push_back(value_type&& val);
template <class... Args>
void emplace_back(Args&&... args);
/* 在vector的末尾插入一个元素,自动的将尺寸扩大1 */
用法: v.push_back(3); v.emplace_back(5); emplace_back比push_back时间性能更优越,
(具体原因不太懂,文档说emplace_back使用args作为传的对象的构造函数的参数,可能
是因为push_back中值传递用的拷贝构造要比直接的构造费时吧)
指定位置插入
iterator insert(const_iterator position, const value_type& val); // 在位置position插入值val
iterator insert(const_iterator position, size_type n, const value_type& val); // 在位置position插入n个值为val的元素
template <typename InputIterator>
iterator insert(const_iterator poosition, InputIterator first, InputIterator last); // 在位置position插入另一个容器中从first到last的值(左闭右开)
iterator insert(const_iterator position, const value_type&& val);
iterator insert(const_iterator position, initializer_list<value_tyep> il);
template <class... Args>
iterator emplace(const_iterator position, Args&&... args);
用法: auto it = v.begin() + 2; v.insert(it, 5); v.insert(it, 3, 5);
int a[] {1, 2, 3, 4}; v.insert(it, a, a + 4); v.insert(it, {1, 2, 3});
v.emplace(it, 5);
(3) 清除元素
iterator erase(const_iterator position); // 删除指定位置的元素'
iterator erase(const_iterator first, const_iterator last); // 删除指定范围的元素,左闭右开
void pop_back(); // 删除最后一个元素
void clear() noexcept; // 清空vector