目录
vector是动态类型的顺序表,任何类型的元素都可以存放。这是C++中的典型容器,接下来将从这几个方面认识与使用vector:构造、迭代器、访问、容量、增删改查、特殊操作。
本文代码均在win10系统下的vs2019验证。
1.构造
函数声明 | 接口说明 |
vector() | 无参构造 |
vector(size_type n,const value_type & val = value_type()) | 构造并初始化n个val |
vector(const vector & x) | 拷贝构造 |
vector(Inputlterator first, Inputlterator last) | 使用迭代器进行区间构造 |
代码一:注意:vector<T> 对象名。这才是正确的语法,不可以省略<T>,这个T代表着,vextor中存储的元素类型。因为vector可以存储任意类型的元素,所以必须指出所存储的元素类型。
除了上述构造函数,C++11还提供了一种新的构造方法,在构造时直接给定数组元素。
//代码一
#include "iostream"
#include "vector"
using namespace std;
void Test() {
//无参构造
vector<int> v1;
//构造v2并初始化10个5
vector<int> v2(10, 5);
//使用迭代器进行区间构造
int arr[] = { 1,2,3,4,5 };
vector<int> v3(arr, arr + sizeof(arr) / sizeof(arr[0]));
//C++11中可以在构造时给定一个数组
vector<int> v4{ 9,8,7,6,5 };
}
int main() {
Test();
}
2.迭代器
iterator的使用 | 接口说明 |
begin() | 获取第一个数据位置的 iterator/const iterator |
end() | 获取最后一个数据下一个位置的 iterator/const iterator |
rbegin() | 获取最后一个数据位置的 iterator/const iterator |
rend() | 获取第一个数据前一个位置的 iterator/const iterator |
前面也说过,迭代器的本质就是指针,我们将它当作指针用就好。但是要注意这几个迭代器究竟指向哪里,下面来看看示意图:
结合函数的功能说明和所画的示意图对迭代器指向的位置有了清晰的认识后,下面来看看它的具体使用。(时刻注意,这几个函数返回的是迭代器类型)
代码二:这里只做给出了一个例子,是因为四个使用方法都相似,就不再赘述了。
使用迭代器时有个小窍门:使用 auto 关键字,因为迭代器类型一般都比较长。
//代码二
#include "iostream"
#include "vector"
using namespace std;
void Test() {
vector<int> v1{ 1,2,3,4,5 };
//迭代器类型比较长,可以用auto代替
vector<int>::iterator it1 = v1.begin();
auto it2 = v1.begin();
}
int main() {
Test();
}
注意迭代器使用时的迭代器失效问题,后面会出一期详细介绍。
3.访问
访问vector主要有三种方法:传统的循环访问、范围for循环、迭代器解引用访问。
代码三:
//代码三
#include "iostream"
#include "vector"
using namespace std;
void Test() {
vector<int> v1{ 9,8,7,6,5 };
//范围for
for (auto& e : v1)
cout << e;
cout << endl;
//size()函数是求vector中有效元素的个数
for (int i = 0; i < v1.size(); i++) {
cout << v1[i];
}
cout << endl;
//正向迭代器遍历
auto it1 = v1.begin();
while (it1 != v1.end()) {
cout << *it1;
it1++;
}
cout << endl;
//反向迭代器访问
auto it2 = v1.rbegin();
while (it2 != v1.rend()) {
cout << *it2;
it2++;
}
}
int main() {
Test();
}
4.容量
函数声明 | 接口说明 |
size() | 获取数据个数 |
capacity() | 获取容量大小 |
empty() | 判断是否为空 |
resize(size_t n,const T& val = T()) | 改变vector的有效元素个数 |
reserve(size_t n) | 根据参数n进行扩容 |
clear() | 清空有效元素 |
(1)解释const T& val = T()
标红的这个表达式中的const T& val = T(),T是一种类型,T的类型取决于vector后的<>,<>中是什么类型,T就是什么类型。
[1]T为内置类型时
T是内置类型是,T() == 0。
代码四:我们可以按用法所说的自己打印int()类型的数据,结果是0。
//代码四
#include "iostream"
#include "vector"
using namespace std;
void Test() {
cout << int() << endl;//0
}
int main() {
Test();
}
[2]T为自定义类型时
当T是自定义类型时,T()调用无参或者全缺省构造函数构造一个匿名对象,若T类中不存在无参全缺省构造方法时报错。
代码五:我们定义一个A类,vectro中存储A类的对象,那么<>中就应该是A。通过在全缺省构造函数中添加语句验证。
//代码五
#include "iostream"
#include "vector"
using namespace std;
class A {
public:
int _n;
A(int n = 10)
:_n()
{
cout << "全缺省调用" << endl;
}
};
void Test() {
vector<A> v;
v.resize(5);
}
int main() {
Test();
}
代码五打印结果:
(2)函数的使用
代码六:注意:resize函数可能会扩容,clear函数只会清空有效元素个数,不会修改容量。
//代码六
#include "iostream"
#include "vector"
using namespace std;
void Test() {
vector<int> v{ 1,2,3,4,5 };
//获取有效元素个数和容量
int vSize = v.size();
int vCapa = v.capacity();
//将有效元素个数设置为8个,多余的空间用5填充
//这个函数内部会自动扩容
v.resize(100, 5);
//扩容
v.reserve(50);
//清空有效元素个数
v.clear();
cout << v.size() << endl;// 0
}
int main() {
Test();
}
(3)验证reserve扩容机制
这里先给出结论:在vs2019中,vector中的reserve函数是按照1.5倍的方式扩容,并且不会把空间缩小,下面给出验证。
代码七:扩容的验证方式:通过不断尾插使vector在合适的时候扩容,扩容后打印空间容量。
空间不缩小的验证方式:通过不断把参数缩小探测vector是否会缩小空间,缩小后打印空间容量。
//代码七
#include "iostream"
#include "vector"
using namespace std;
void Test() {
vector<int> v{ 1,2,3,4,5 };
cout << "容量增加情况:";
for (int i = 0; i < 300; i++) {
int oldCa = v.capacity();
//循环逐个往数组中添加元素观察容量变化情况
v.push_back(1);
if (oldCa != v.capacity())
cout << oldCa << " ";
}
cout << endl << endl;
cout << "容量减少情况:";
for (int i = 300; i >= 0; i--) {
int oldCa = v.capacity();
v.reserve(i);
if (oldCa != v.capacity()) {
cout << v.capacity() << " ";
}
}
}
代码七的打印结果:证实了1.5倍扩容与不缩小。
(4)resize的填充机制
resize函数语法:resize(size_t newsize,size_t val)。
[1]capacity >newsize > oldsize:不扩容,直接在vector末尾填充newsize -oldsize个值为val的元素
[2]capacity <newsize:先扩容再填充
[3]oldsize>newsize:直接将有效元素个数缩减到newsize
5.增删改查
函数声明 | 功能说明 |
operator[size_t pos] | 像数组一样访问 |
at(size_t pos) | 访问pos位置元素 |
front() 【当vector中没有元素,front和back都会报错】 | 访问或修改(非const才可以修改)vector的起始位置的元素 (返回值是引用,所以可以修改) |
back() | 访问或修改(非const才可以修改)vector的最后一个位置的元素 |
push_back(元素) | 尾插 |
pop_back() | 尾删 |
assign(iterator first,iterator lat) | 把迭代器这个闭区间内的元素放到vector中替代原本元素 |
assign(size_t n,const T& val) | 往vector中放n个val,替代原本元素 |
find(iterator first,iterator last,T val) | 在区间中查找val,返回迭代器(vector没有find函数,这是算法模块的函数) |
insert(iterator it,const T& x) | 把x插到迭代器it指向的位置 |
erase(iterator it) | 把迭代期it指向的位置元素删除(返回值是后一个元素的迭代器) |
erase(iterator first,iterator last) | 删除这个闭区间内的元素 |
swap() | 交换 |
代码八:注意:front 和 back 函数使用时vector中必须有元素,否则会报错。
vector中没有find函数,这里使用的是算法模块的find函数。
erase函数的返回值是被删除元素的后一位元素的迭代器。
//代码八
#include "iostream"
#include "vector"
using namespace std;
void Test() {
vector<int> v{ 1,2,3,4,5 };
//像数组一样访问
cout << v[0] << endl;
//使用at访问
cout << v.at(0) << endl;
//访问头部元素(vector中必须要有元素才行,否则报错)
cout << v.front() << endl;
//访问尾部元素,注意事项同上
cout << v.back() << endl;
//尾插
v.push_back(6);
//尾删
v.pop_back();
//把arr中的元素放到v中,v中原本元素会被替代掉
int arr[] = { 9,8,7,7,8,9,8,7 };
v.assign(arr, arr + sizeof(arr) / sizeof(arr[0]));
//往v中放10个2,替代原本元素
v.assign(10, 2);
//往第一个元素的位置插入6
v.insert(v.begin(), 6);
//查找6所在位置的迭代器,没有则返回end()
vector<int>::iterator it = find(v.begin(), v.end(), 6);
//删除第一个元素
v.erase(v.begin());
//删除全部元素
v.erase(v.begin(), v.end());
//交换
vector<int> v1{ 1,2,3 };
vector<int> v2{ 5,6,7 };
v1.swap(v2);
}
int main() {
Test();
}
6.特殊操作
函数声明 | 功能说明 |
sort(iterator first,iterator last) | 排序(升序) |
sort函数也是算法模块的函数,使用时应加上头文件:#include "algorithm"
代码九:sort函数是排升序。
//代码九
#include "iostream"
#include "vector"
#include "algorithm"
using namespace std;
void Test() {
vector<int> v{ 1,7,3,9,5 };
sort(v.begin(), v.end());
}
int main() {
Test();
}