🚃vector - 向量

STL中vector类的详细介绍

vector 容器基本概念

vector的数据安排及操作方式,与array非常相似,两者的唯一差别在于空间的运用的灵活性。

array是静态空间,一旦配置了一般不能改变,如果要改变空间大小,需要自行完成以下三个步骤:

  • 配置一块新的空间

  • 将旧数据搬往新的空间

  • 释放原来的空间

vector是动态空间,但其实vector的动态也是对于上述过程的封装,并且vector配置空间的策略也考虑了运行成本,采用特定的扩展的策略(并不是简单的成倍扩展)。

vector 迭代器

vector维护一个线性空间,所以不论元素类型如何,普通指针都可以作为vector的迭代器。

  • 因为vector迭代器所需要的行为,如operator*operator->operator++operator--operator+operator-operator+=operator-=,普通指针天生具备。

  • vector指针支持随机存取,而普通指针正有着这样的能力。

所以,vector提供的是随机访问迭代器(Random Access Iterator),其内部用普通指针实现。

使用迭代器进行正序遍历

for (vector<T>::iterator it = v.begin(); it != v.end(); it++)
{
    cout << *it << endl;
}
/**
 * 1. 迭代器的声明方式:  容器类型::迭代器类型
 * 2. 顺序首尾迭代器由begin()和end()方法生成
*/

使用迭代器逆序遍历

for (vector<T>::reverse_iterator it = v.rbegin(); it != v.rend(); it++)
{
    cout << *it << endl;
}
/**
  * 1. 逆向迭代器不再是iterator,而是reverse_iterator
  * 2. 逆序首位迭代器由rbegin()和rend()方法生成
*/

判断迭代器是否能随机访问的方法

用多了自然就背上了,下面给出一种现场测试的方法。

iterator++
iterator--
//通过编译,至少是双向迭代器
  
iterator = iterator + 1
//通过编译,则是随机访问迭代器

vector 数据结构

vector采用的数据结构非常简单,线性连续空间,它以两个迭代器_Myfirst_Mylast分别指向配置得来的连续空间中已被使用的范围,并以迭代器Myend指向整块连续内存空间的尾端。

为了降低空间配置时的成本,vector实际配置的大小可能比用户端需求大一些,以备将来可能的扩充,这便是容量的概念。

  • 一个vector容器的容量永远大于等于其大小,一旦容量等于大小,便是满载,下次再有新增元素,整个vector容器就得另觅居所。

所谓动态增加大小,并不是在原空间之后续接新空间(因为无法保证原空间之后尚有可配置的空间),而是一块更大的内存空间,然后将原数据拷贝新空间,并释放原空间。

因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了

vector常用API操作

API = Applicational Programming Interface

vector 构造函数

vector<T> v; // 采用模版类实现,默认构造函数
vector<T> v(T* v1.begin(), T* v1.end()); // 将v1[begin(), end())区间中的元素拷贝给本身
vector<T> v(int n, T elem); // 将n个elem拷贝给本身
vector<T> v(const vector<T> v1); // 拷贝构造函数

下面对于第二种构造方式给出一个特殊的例子:

int array[5] = {1, 2, 3, 4, 5};
vector<int> v(array, array + sizeof(array) / sizeof(int));
// 联系我们之前提到的vector迭代器本质上是指针就不难理解了

vector 常用赋值操作

由于vector采用模版类实现,其完整的函数声明会稍显复杂,下面方法的演示会省略类型界定。

assign(beg, end); // 将[beg, end)区间中的数据拷贝复制给本身
assign(n, elem); // 将n个elem拷贝给本身
vector& operator=(const vector& vec); // 重载赋值操作符

互换操作也可视为一种特殊的赋值:

swap(vec); //将vec与本身的元素互换

巧用swap来收缩空间:

vector<int>(v).swap(v);
// vector<int>(v): 利用拷贝构造函数初始化匿名对象
// swap(v): 交换的本质其实只是互换指向内存的指针
// 匿名对象指针指向的内存会由系统自动释放

vector 大小操作

int size(); // 返回容器中的元素个数
bool empty(); // 判断容器是否为空

void resize(int num); 
// 重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
// 若容器变短,则末尾超出容器长度的元素被删除
void resize(int num, T elem); 
// 重新指定容器的长度为num,若容器变长,则以elem填充新位置。
// 若容器变短,则末尾超出容器长度的元素被删除

int capacity(); // 返回容器的容量
void reserve(int len); 
// 容器预留len个元素长度,预留位置不初始化,元素不可访问

vector 数据存取操作

T& at(int idx); // 返回索引idx所指的数据,如果idx越界,抛出out_of_range异常
T& operator[](int idx); // 返回索引idx所指的数据,如果idx越界,运行直接报错

T& front(); // 返回首元素的引用
T& back(); // 返回尾元素的引用

vector插入和删除操作

insert(const_iterator pos, T elem); // 在pos位置处插入元素elem
insert(const_iterator pos, int n, T elem); // 在pos位置插入n个元素elem
insert(pos, beg, end); // 将[beg, end)区间内的元素插到位置pos
push_back(T elem); // 尾部插入元素elem
pop_back(); // 删除最后一个元素

erase(const_iterator start, const_iterator end); // 删除区间[start, end)内的元素
erase(const_iterator pos); // 删除位置pos的元素

clear(); // 删除容器中的所有元素

至此,读者应当对vector的特点及基本操作有了较为全面的认识,使用时API记不清可以回头多看。

最后更新于