一、介绍
C++的vector也被称为单端数组,它的数据结构与数组非常类似。
一般用于在尾部进行插入和删除的操作。
二、动态扩充
与数组不同,vector可以根据需求动态扩展。这里的动态扩展指的是它的空间大小会随着需求而增长,但并不是在原空间的基础上继续增加,而是:
1. 找到一块新的更大的空间
2. 将原空间的数据拷贝到新空间
3. 释放原空间
三、vector的使用
※ ※ ※ ※ 在使用vector时,需要添加头文件#include <vector> ※ ※ ※ ※
3.1 vector初始化
vector提供几种构造函数,用于初始化。vector是一个泛型类,因此在初始化时候,需要确定自身元素的类型,也就是指定具体的泛型,如下所示:
声明 | 解释 |
vector<T> v; | 默认构造函数,T为模板类型 |
vector<T>(v.begin(), v.end()); | 将另一个向量的v[begin(), end()]区间拷贝给自身 |
vector<T>(int n, T elem) | 将n个elem拷贝给自身 |
vector<T>(const vector &v) | 拷贝构造函数,将v的内容拷贝给自身 |
vector<string> v0;//初始化一个元素类型为string的vector对象 v0
vector<string> v1(v0.begin()+1, v0.end());//用v0的 第二个元素 到 最后一个元素 初始化v1
vector<char> v2(5, 'W');//用5个字符W初始化v2
vector<string> v3(v0);//用v0初始化v3
3.2 vector赋值
vector的赋值通过运算符=和assign函数实现:
声明 | 解释 |
vector& operator=(const vector &v) | 将v的内容拷贝给自身 |
assign(vector<T>::iterator begin, vector<T>::iterator end); | 将 [begin, end)区间 拷贝给自身 |
assign(int n, T elem); | 将n个elem拷贝给自身 |
template<typename T>
void printVector(vector<T> &v) {
for (T elem : v) {
cout << elem;
}
cout << endl;
}
void demo_vector() {
vector<char> v0(5, 'A');//v0 = AAAAA
printVector(v0);
vector<char> v1 = v0; //v1 = AAAAA
printVector(v1);
v1.assign(v0.begin() + 1, v0.end());//v1 = AAAA
printVector(v1);
v1.assign(5, 'B');//v1 = BBBBB
printVector(v1);
}
3.3 vector容量与大小
有关获取、设置vector容量及大小的函数,如下所示:
声明 | 解释 |
capacity() | 获取当前vector的容量 |
empty() | 判断当前vector是否为空 |
size() | 获取当前vector中元素的个数 |
resize(int num) | 将vector的长度重新设置为num 1. 如果容量变大,则以默认值填充新位置 2. 如果容量变小,则将末尾超出容器长度的元素删除 |
resize(int num, T elem) | 将vector的长度重新设置为num 1. 如果容量变大,则以elem填充新位置 2. 如果容量变小,则将末尾超出容器长度的元素删除 |
template<typename T>
void printVector(vector<T> &v) {
cout << '[';
for (T elem : v) {
cout << elem;
}
cout << ']' << endl;
}
void demo_vector() {
vector<int> v0(5, 6);//v0 = 66666
cout << "v0.empty() : " << boolalpha << v0.empty() << endl; //是否为空:false
cout << "v0.capacity() : " << v0.capacity() << endl;//容量大小:5
cout << "v0.size() : " << v0.size() << endl;//元素个数:5
v0.resize(7);//容量增大,默认值0填充
printVector(v0);//6666600
v0.resize(3);//容量减小
printVector(v0);//666
v0.resize(9, 8);//容量增大,用‘B’填充
printVector(v0);//666888888
}
程序运行结果为:
3.3 vector插入
vector的插入,常规的有insert函数,除此以外还有push_back函数。
声明 | 解释 |
push_back(T ele) | 在尾部插入ele |
insert(const_iterator pos, T ele) | 向迭代器pos位置插入ele |
insert(const_iterator pos, int n, T ele) | 向迭代器pos位置插入n个ele |
vector<int> v0(5, 6);//v0 = 66666
v0.push_back(7);//v0 = 666667
v0.insert(v0.begin(), 8);//v0 = 8666667
v0.insert(v0.begin() + 2, 3, 5);//v0 = 8655566667
3.4 vector删除
vector删除元素的函数有clear()、erase()、pop_back()。
声明 | 解释 |
push_pop() | 删除尾部最后一个元素 |
clear() | 删除所有元素 |
erase(const_iterator pos) | 删除迭代器pos位置指向的那个元素 |
erase(const_iterator begin, const_iterator end) | 删除[begin, end) 区间的元素 |
//用于输出向量元素的函数
template<typename T>
void printVector(vector<T> &v) {
if (v.empty()) {
cout << "vector is empty now, no elems." << endl;
return;
}
cout << '[';
for (T elem : v) {
cout << elem;
}
cout << ']' << endl;
}
vector<int> v0;
for (int i = 0; i < 10; i++) {
v0.push_back(i);
}
cout << "v0:";
printVector(v0);//v0 = 0123456789
v0.pop_back();
cout << "After pop_back, v0:";
printVector(v0);//v0=012345678
v0.erase(v0.begin());
cout << "After erase v0.begin(), v0:";
printVector(v0);//v0=12345678
v0.erase(v0.begin() + 1, v0.end() - 2);
cout << "After erase v0.begin()+1 to v0.end()-2, v0:";
printVector(v0);//v0=178
v0.clear();
cout << "After clear, v0 : ";
printVector(v0);//empty
程序执行结果如下:
3.5 vector存取
vector存取元素,通常采用以下三个函数和运算符[ ]:
声明 | 解释 |
T at(int index) | 返回下标index指向的那个元素的值 |
T front() | 返回向量中第一个元素的值 |
T back() | 返回向量中最后一个元素的值 |
operator[index] | 返回下标index指向的那个元素的值 |
vector<int> v0;
for (int i = 0; i < 10; i++) {
v0.push_back(i);
};//v0 = 0123456789
cout << "v0.at(6) : 6 == " << v0.at(6) << endl;//6
cout << "v0.front() : 0 == " << v0.front() << endl;//0
cout << "v0.back() : 9 == " << v0.back() << endl;//9
cout << "v0[7] : 7 == " << v0[7] << endl;//7
3.6 两个vector互换元素
如果想将v1和v2两个vector中的元素互换,应该采用swap()函数,声明如下:
声明 | 解释 |
void swap(vector v) | 将当前向量的元素与v的元素互换 |
//输出向量所有元素的函数
template<typename T>
void printVector(vector<T> &v) {
if (v.empty()) {
cout << "vector is empty now, no elems." << endl;
return;
}
cout << '[';
for (T elem : v) {
cout << elem;
}
cout << ']' << endl;
}
vector<int> v0, v1;
for (int i = 0; i < 9; i++) {
v0.push_back(i);
v1.push_back(i + 1);
};
cout << "Before swap : " << endl;
cout << "v0 : "; printVector(v0);//v0 = 012345678
cout << ", v1 : "; printVector(v1);//v1 = 123456789
v0.swap(v1);
cout << "After swap : " << endl;
cout << "v0 : "; printVector(v0);//v0 = 123456789
cout << ", v1 : "; printVector(v1);//v1 = 012345678
3.7 vector预留空间
vector可以reserve函数预留空间,来减少vector在动态扩容时候的扩展次数。
声明 | 解释 |
reserve(int len) | 为当前vector预存len个元素的长度 (预留位置不初始化,这些元素不可访问) |
为了测试reserve函数使用与否的区别,我们就要观察在相同条件下的扩容次数。通过前文我们知道,vector的动态扩容是申请一段更大的空间,因此每次扩容的首地址会变化。
首地址变化的次数 = 扩容次数,由此举例如下:
int demo_vector(bool used_reserve) {
vector<int> v;
int extendNum = 0;//用于记录v0的扩容次数
int* pre_v_address = NULL;//用于记录v0 上次插入元素后,空间的首地址
if (used_reserve) {
v.reserve(500);
}
//将0-999这1000个元素插入v0中
for (int i = 0; i < 1000; i++) {
v.push_back(i);
if (pre_v_address != &v[0]) {
cout << "Extend when insert " << i << endl;
//如果v0上次的空间首地址 不等于 当前第一个元素的首地址
//说明申请了新空间,发生了动态扩容
pre_v_address = &v[0];//令本次空间首地址 为 当前第一个元素的首地址
extendNum++;//扩容次数+1
}
};
return extendNum;
}
int main() {
cout << "With reserve(), extend number is : " << demo_vector(true) << endl;
cout << "Without reserve(), extend number is : " << demo_vector(false) << endl;
return 0;
}
当demo_vector函数的参数分别为true和false时,分别代表采用和不采用reserve函数。程序运行结果如下:
结果中我们可以观察到,在包含初始申请空间的情况下,适应reserve仅仅扩充3次
没有使用reserve的情况下,扩充次数达到了18次。