前言:在前面的文章中我们已经介绍了string的用法及其模拟实现,本篇文章就进入到vector的学习。学习STL还是遵循学会使用,理解底层的步骤学习,所以本篇文章会介绍vector的使用。
Vector是一种动态数组,能够自动管理内存并根据需要调整大小。它属于C++标准模板库(STL),提供高效的随机访问和尾部插入/删除操作。
构造函数声明 | 接口说明 |
|---|---|
vector() | 无参构造(默认构造函数) |
vector(size_type n, const value_type& val = value_type()) | 构造并初始化 n 个值为 val 的元素(val 默认为 value_type 的默认值) |
vector(const vector& x) | 拷贝构造(通过另一个 vector 对象 x 初始化) |
vector(InputIterator first, InputIterator last) | 使用迭代器范围 [first, last) 进行初始化构造 |
要点说明: 无参构造:创建空的容器,通常用于后续动态添加元素。 带数量及默认值的构造:预先分配空间并填充指定值,适合需要预初始化的情况。 拷贝构造:深拷贝另一个 vector 的所有元素,独立于原对象。 迭代器范围构造:支持从其他容器的迭代器(如数组、list 等)初始化,灵活性高。
代码示例:
#include<vector>
#include<iostream>
using namespace std;
int main()
{
//默认构造
vector<int> v1;
//使用n个值构造初始化
vector<int> v2(10, 1);//用10个1初始化v2
for (auto e : v2)
{
cout << e<< " ";
}
cout << endl;
//拷贝构造
vector<int> v3(v2);//v2拷贝给v3
for (auto e : v3)
{
cout << e << " ";
}
cout << endl;
//使用迭代器初始化
vector<int>::iterator it = v2.begin();
vector<int> v4(v2.begin(), v2.end());
for (auto e : v4)
{
cout << e << " ";
}
return 0;
}运行结果:


int main()
{
//初始化列表初始化就是像数组一样使用花括号初始化
int a[] = { 10, 20, 30 };
auto il1 = { 10, 20, 30 };
auto il2 = { 10, 20, 30,1,1,1,1,1,1,1 };
cout << typeid(il1).name() << endl;//使用typeid查看真实的类型是 initializer_list
//cout << il1.begin() << endl; li1与a(整型)的地址相似说明它们类型是一样的
//cout << a << endl;
vector<int> v1 = { 10, 20, 30 };
vector<int> v2 = { 10, 20, 30,1,1,1,1,1,1,1 };
for (const auto& e : v1)
{
cout << e << " ";
}
cout << endl;
}使用花括号初始化的逻辑:花括号的内容会被隐式类型转化成initializer_list类型,然后再调用对应的构造函数。
方法 | 返回类型 | 作用描述 |
|---|---|---|
begin() | iterator/const_iterator | 获取容器第一个数据位置的迭代器(非const版本可能修改元素) |
end() | iterator/const_iterator | 获取容器最后一个数据的下一个位置的迭代器(哨兵位,不可解引用) |
rbegin() | reverse_iterator | 获取容器最后一个数据位置的逆向迭代器(实际是end()-1的封装) |
rend() | reverse_iterator | 获取容器第一个数据前一个位置的逆向迭代器(实际是begin()-1的封装) |
要点说明: begin() 和 end():通常用于正向遍历容器。 rbegin() 和 rend():用于逆向遍历容器。 const 版本:如 cbegin()/cend() 返回 const_iterator,确保遍历时不修改元素。
代码示例:
#include<vector>
#include<iostream>
using namespace std;
int main()
{
vector<int> v1 = { 1, 2, 3 };
//正向迭代器
vector<int>::iterator it1 = v1.begin();
while (it1 != v1.end())
{
cout << *it1<<" ";
++it1;
}
cout << endl;
//反向迭代器
vector<int>::reverse_iterator it2 = v1.rbegin();
while (it2 != v1.rend())
{
cout << *it2<<" ";
++it2;
}
cout << endl;
//范围for (推荐)
for (auto e : v1)
{
cout << e <<" ";
}
}运行结果:

迭代器图解:

接口名称 | 功能描述 | 备注 |
|---|---|---|
size_type size() const | 获取当前存储的数据个数 | 实际元素数量 |
size_type capacity() const | 获取当前分配的容量大小 | 预分配内存空间大小 |
bool empty() const | 判断容器是否为空 | 等价于size==0 |
void resize (size_type n, value_type val = value_type()); | 改变容器的实际元素数量(size) | 可能影响capacity |
void reserve (size_type n) | 改变容器的预分配容量(capacity) | 不影响现有元素 |
要点说明: vector的capacity的增容的倍数是看编译器,例如vs下是二倍扩容,而g++下是1.5倍扩容,具体扩容倍数是根据需求来定的!
代码示例:
#include<vector>
#include<iostream>
using namespace std;
int main()
{
vector<int> v1(10, 11);
//有效数据个数
cout << v1.size() << endl;
//空间大小
cout << v1.capacity() << endl;
if (!v1.empty())//判断vector是否为空
{
for (auto e : v1)
{
cout << e << " ";
}
}
cout << endl;
//扩容 扩容的空间使用6来填充
v1.resize(20, 6);
cout <<"size:"<< v1.size() << endl;
cout <<"capacity:"<< v1.capacity() << endl;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
//resise缩容
v1.resize(5);//缩小的是有效数据个数
cout << "size:" << v1.size() << endl;
cout << "capacity:" << v1.capacity() << endl;
vector<int> v2;
v2.reserve(10);
cout << "size:" << v2.size() << endl;
cout << "capacity:" << v2.capacity() << endl;
return 0;
}运行结果:

接口名称 | 功能描述 | 备注 |
|---|---|---|
void push_back (const value_type& val) | 在vector尾部插入元素 | 时间复杂度O(1)(均摊) |
void pop_back() | 删除vector尾部元素 | 不会返回被删除元素 |
find | 在范围内查找指定值 | 需包含<algorithm>头文件,返回迭代器 |
iterator insert (iterator position, const value_type& val); | 在指定迭代器位置前插入元素 | 可能导致迭代器失效 |
iterator erase (iterator position) | 删除指定迭代器位置的元素 | 返回指向下一元素的迭代器 |
void swap (vector& x) | 交换两个vector的存储空间 | 常数时间复杂度 |
reference operator[] (size_type n) | 通过下标随机访问元素 | 不进行越界检查 |
要点说明:
insert 与 erase的返回值均为指向操作后位置的迭代器,需注意迭代器失效问题。(在实现部分讲)operator[] 和 at()的区别在于后者会进行边界检查并抛出异常。find:采用的是算法库的find,传入的参数为一个迭代器区间,加上一个val(所要查找的值)。
代码示例:
#include<vector>
#include<iostream>
using namespace std;
int main()
{
vector<int> v1;
//尾插
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
cout << "size:" << v1.size() << endl;
//删除数据
v1.pop_back();
cout << "size:" << v1.size() << endl;
//insert 效率较低涉及数据的移动
vector<int> v2;
v2.push_back(1);
v2.push_back(2);
v2.push_back(3);
v2.push_back(5);
v2.insert(v2.begin() + 3, 100);
//(算法库的)find+insert
auto it = find(v2.begin(), v2.end(), 2);
if (it != v2.end())
{
//在该迭代器位置处插入50
v2.insert(it, 50);
}
//erase 效率较低涉及数据的移动
v2.erase(v2.begin() + 3);//删除下标为3位置处的数据
//find+erase
auto it1 = find(v2.begin(), v2.end(), 100);
if (it1 != v2.end())
{
v2.erase(it1);
}
//下标访问
cout<<v2[5]<<endl;
return 0;
}struct A
{
A(int a1, int a2)
:_a1(a1)
,_a2(a2)
{
cout << "A(int a1, int a2)" << endl;
}
A(const A& aa)
:_a1(aa._a1)
,_a2(aa._a2)
{
cout << "A(const A& aa)" << endl;
}
int _a1;
int _a2;
};
int main()
{
//push_back与emplace_back效率的比较
vector<A> v2;
A aa1(1, 1);
v2.push_back(aa1);
cout << endl;
v2.push_back(A(2,2));
cout << endl;
v2.push_back({3,3});
cout << endl;
cout << "**************************" << endl;
v2.emplace_back(aa1);
cout << endl;
v2.emplace_back(A(2, 2));
cout << endl;
v2.emplace_back( 3,3 );
//emplace_back不支持初始化列表初始化
//v2.emplace_back({ 3,3 });
//遍历自定义类型可以使用范围for也可以使用结构化绑定
//C++11 范围for
for (auto& aa : v2)
{
cout << aa._a1 << ":" << aa._a2 << endl;
}
// C++17 结构化绑定
//auto [x, y] = aa1;//x y为A类型的成员变量 x y 的名字可以任取
for (auto& [x, y] : v2)
{
cout << x << ":" << y << endl;
}
}
以上就是本篇文章的所有内容了,感谢各位大佬观看,制作不易还望各位大佬点赞支持一下!有什么问题可以加我私信交流! |
|---|