C++《vector》
mljy. 2024-10-24 17:35:02 阅读 89
#1024程序员节|征文#
在之前C++《string》当中我们学习了string的各个接口的使用以及在string模拟实现当中试着实现了string当中日常我们会较为频繁使用到的接口,通过模拟实现我们对string的底层有了更深层次的理解。接下来在本篇当中我们将进行进行STL的学习,在本篇我们要学习的容器是vector也就是之前在数据结构学习过的顺序表,在学习vector过程中由于STL的接口大部分都是相识的因此在学习完string后学习vector将会轻松许多。在了解vector过程中最重要的是要了解深浅拷贝,这部分的内容将在本篇之后的vector模拟实现当中重点来讲解。接下来就开始本篇的学习吧!!!
1.⭐构造函数
vector::vector - C++ Reference
在vector当中构造函数提供了以上的4个接口,这其中包括一个拷贝构造函数,接下来我们就来一一了解这些接口该如何使用
在了解vector的构造之前先要了解的是STL当中的vector是用模板实现的,这样是为了vector内的数据类型不被限定死,这样创建的vextor对象内的数据类型就可以根据用户显示写大的来确定
在vector构造函数的接口当中以下几个是和我们之前学习的string类似的
<code>#include<iostream>
#include<vector>
using namespace std;
int main()
{
//无参构造
vector<int> v1;
//一个元素构造
vector<int> v2(1);
//n个一样的元素构造
vector<int> v3(5, 6);
return 0;
}
接下来要了解的两个接口就不和之前学习的string不同
template <class InputIterator>
vector (InputIterator first, InputIterator last,const allocator_type& alloc =allocator_type());
以上这个接口是使用迭代器区间来实现vector对象的初始化构造,在此迭代器fist是输入的开始,last迭代器是结束位置,最终范围是 [first,last),该区间是左闭右开的,构造的过程中不包括last指向的值
使用例如以下示例
#include<iostream>
#include<vector>
using namespace std;
int main()
{
//无参构造
vector<int> v1;
//一个元素构造
vector<int> v2(1);
//n个一样的元素构造
vector<int> v3(5, 6);
//使用迭代器区间来构造
vector<int> v4(v3.begin(), v3.end()-1);
return 0;
}
在以上代码中对象v4的初始化就是使用迭代器区间来实现,在此开始时从v3.begin(),结束位置是v3.end(),并且最后的数据不包括v3.end()位置的元素
因此v4初始化之后该对象内部数据就为6 6 6 6
在此我们还要了解vector初始化的方式是通过调用initializer_list来完成初始化,这个接口是在C++11之后支持的
要了解这个构造的接口是如何实现的我们就要先来了解initializer_list是什么
initializer_list是一个C++11当中增加的,在此我们可以认为将一系列的数据使用{}括起来就会初始化出一个对象,该对象的类型就是initializer_list。可以认为initializer_list也是一个容器
在initializer_list当中成员函数非常的简单,就支持迭代器和size
在了解了initializer_list之后我们就可以知道在vector构造当中提供的initializer_list接口就可以实现用户直接将使用{}括起来的数据直接给vector对象来实现初始化构造,在该过程其实可以理解为会在底层开出一块内存空间将{}内的数据存储到内存空间内,并且还会有两个指针分别指向空间的起始和终止位置,最后将该空间内的数据依次插入到vector对象内实现初始化
例如以下示例:
<code>#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v5({ 1,2,3,4 });
vector<int> v6 = { 1,2,3,4 };
return 0;
}
在以上代码中对象v5就是通过调用vector构造函数当中的initializer_list接口来直接完成构造。而对象v6其实语法逻辑和v5有所不同的是通过隐式类型转换,是将initializer_list对象先构造出一个vector的临时对象之后再去拷贝构造,但编译器在这样的连续构造+拷贝构造就会演化为直接构造
接下来了解vector当中的拷贝构造函数
vector(const vector& x)就是将对象x的拷贝数据拷贝给新创建的对象,在此过程进行的是深拷贝,具体实现在之后的vector模拟实现章节会进行解析
例如以下示例:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v6 = { 1,2,3,4 };
vector<int> v7(v6);
return 0;
}
以上代码就是使用对象v6来拷贝构造v7
2.⭐析构函数
vector::~vector - C++ Reference
在vector当中也提供了析构函数,该函数会在对象销毁时自动调用,不需要我们显示的调用
3.⭐赋值运算符重载
vector::operator= - C++ Reference
在vector当中也提供了赋值运算符重载函数,有了这个函数我们就可以将两个已经初始化的vector对象之间进行赋值
例如以下示例:
<code>#include<iostream>
#include<vector>
using namespace std;
int main()
{
//无参构造
vector<int> v1;
//一个元素构造
vector<int> v2(1);
v1 = v2;
return 0;
}
以上就在对象v1和v2在初始化之后将对象v2赋值给v1
4.容量操作
在vector当中容量的操作除了以下讲解的其实还有其他的操作,但其他的函数操作在日常当中的使用较少,并且这些函数和之前我们学习string时类似,因此你如果想详细了解可以观看以下文档
vector - C++ Reference
4.1 ⭐size
在vector类当中也提供了size这个函数来得到对象内的有效元素个数
4.2 ⭐capacity
在vector类中的capacity函数是用来得到类对象当中的空间大小也就是容量
4.3 ⭐resize
在vector类当中也提供了resize来将对象内的有效元素个数改为指定值n,这时就会出现以下三种情况
1.此时的有效数据个数比n大,那么调用resize之后就会将原有效数据个数截断到n个
2. 此时的有效数据个数比n小,并且n比当前的内存空间大小小,那么这时调用resize就会将对象当中从原有效数据之后到n个元素都使用指定值val来填充
3..此时的当前的内存空间大小比n小,那么这时调用resize就会先将该对象进行内存空间的扩容之后再进行以上的2操作
4.4⭐ reserve
在vector类当中也提供了reserve来实现将对象的内存空间扩容到指定值n,当n大于原空间大小时会进行扩容,但当n小于原空间的大小时一般不会进行缩容
5. 访问以及遍历操作
5.1 ⭐下标+[ ]
vector::operator[] - C++ Reference
在vector当中由于底层和顺序表类似物理空间是连续的因此能通过下标+[ ]的方式来访问vector对象内的元素,并且和string一样也提供了const对象和非const对象两个接口。对于非const对象来说使用下标+[ ]访问元素既可读也可以写;但对于const对象来说使用下标+[ ]访问元素只能读
例如以下示例:
<code>#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v3(5, 6);
for (int i = 0; i < v3.size(); i++)
{
cout << v3[i] << " ";
}
return 0;
}
5.2 ⭐迭代器
在vector类当中和string一样也提供了正向迭代器和 反向迭代器,并且以上迭代器都提供了const接口和非const接口
例如以下示例:
<code>#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v5({ 1,2,3,4 });
//vector<int>::iterator i1 = v5.begin();
auto i1 = v5.begin();
while (i1 != v5.end())
{
cout << *i1 << " ";
i1++;
}
cout << endl;
auto i2 = v5.rbegin();
while (i2 != v5.rend())
{
cout << *i2 << " ";
i2++;
}
cout << endl;
return 0;
}
5.3 ⭐范围for
在vector当中由于支持迭代器那么就可以支持范围for来遍历对象内的元素
例如以下示例:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v6 = { 1,2,3,4 };
for (auto x : v6)
{
cout << x << " ";
}
return 0;
}
6.修改操作
在vector提供了以下的函数来实现对对象内数据的修改
以上两个函数emplace和emplace_back是string中没有的,在此在本篇当中先不讲这两个函数该如何使用,这两个函数list当中也是有的因此将在list篇章中细致的讲解
6.1 assign
vector::assign - C++ Reference
在vector当中也支持assign将原vector对象内的数据进行重覆盖,在此和string不同的是在调用这个接口需要传的是迭代器区间
例如以下示例:
<code>#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v5({ 7,8,9,10 });
vector<int> v6 = { 1,2,3,4 };
for (auto x : v6)
{
cout << x << " ";
}
return 0;
}
6.2 ⭐push_back与pop_back
在vector当中提供 push_back与pop_back两个函数分别来实现尾插和尾删
例如以下示例:
<code>#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v6 = { 1,2,3,4 };
v6.pop_back();
v6.push_back(88);
v6.push_back(99);
for (auto x : v6)
{
cout << x << " ";
}
return 0;
}
6.3 insert和erase
vector::insert - C++ Reference
vector::erase - C++ Reference
在vector当中也提供了insert和erase来实现任意位置的插入和删除
在此的插入和删除要传的参数和之前string有所不同,vector中的inser和erase需要传的是迭代器区间或者是一个迭代器
例如以下示例:
<code>#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v5({ 7,8,9,10 });
vector<int> v6 = { 1,2,3,4 };
v6.insert(v6.begin(), 999);
v6.insert(v6.begin()+1,2, 888);
v6.erase(v6.end() - 1);
v6.erase(v6.end() -3, v6.end() - 1);
for (auto x : v6)
{
cout << x << " ";
}
return 0;
}
注意:在使用迭代器区间删除时,删除区间是左闭右开的,删除不包括最后位置的值
以上就是vector使用的介绍,通过本篇讲解你会发现string和vector内大部分的函数都是相识的,因此在学习了string之后再了解vector就任意多了,这是因为STL大部分都是相通的,学习了一个容器之后后面的容器的使用就较为任意上手了。
本篇的内容到这里就结束了,接下来再下一篇vector模拟实现当中我们将会来试着自己实vector,在这个过程当中会了解到vector迭代器失效这个在vector非常重要的知识点,未完待续……
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。