这里写目录标题
什么是vectorvector的定义reserve
vector数据插入push_backinsertresizeassign
vector数据的删除pop_backeraseclear
vector性质查看sizecapacityemptymax_sizevector元素修改operator[ ]atfrontback
vector其他函数operator=swap
什么是vector
vector是表示可变大小数组的序列容器。就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好。
vector的定义
首先我们得知道一件事:为了让vector能够容乃各种各样不同类型的数据,我们这里就得使用模板来处理各种各样的情况,而且这里是类模板所以我们在创建vector对象的时候就得显示实例化,然后这个模板里面有这么一句话 class Alloc = allocator,这里大家就不用管,他已经给了缺省参数而且这句的用处是创建一个内存池用来加快内存分配的速度,接下来我们再来看看vector有哪些不同类型的构造函数: 第一种:
explicit vector (const allocator_type& alloc = allocator_type());
这种构造函数只有一个参数,这个参数跟内存池有关并且还给了这个参数一个缺省值,所以对于第一种形式我们就可以认为他是一个无参初始化,这种初始化的结果就是vector对象里面什么内容都没有,我们可以看看下面的函数来了解这个构造函数的使用:
#include
#include
using namespace std;
void test1()
{
vector v1;//创建一个空顺序表用来装char类型的数据
for (auto ch : v1)
{
cout
int a = int();
double b = double();
char c = char();
cout
_year = year;
_month = month;
_day = day;
}
void print()
{
printf("year的值为:%d ", _year);
printf("month的值为:%d ", _month);
printf("day的值为:%d ", _day);
printf("\n");
}
private:
int _year;
int _month;
int _day;
};
void test2()
{
Date d1(2022, 12, 12);
vector v1(3);
vector v2(3,d1);
cout
v.print();
}
}
这段代码的运行结果为: 第三种形式:
template
vector (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
这种形式就是用迭代器来初始化新创建出来的对象,这里有三个参数第一个就是迭代器开始的地方,第二个参数就是迭代器结束的地方,第三个参数不用管,那么下面就是该形式使用的方法:
void test3()
{
vector v;
v.push_back(Date(2018, 11, 11));
v.push_back(Date(2019, 11, 11));
v.push_back(Date(2020, 11, 11));
v.push_back(Date(2021, 11, 11));
v.push_back(Date(2022, 11, 11));
vector::iterator it1 = v.begin()+1;
vectorv1(it1, v.end() - 1);
for (auto v : v1)
{
v.print();
}
}
代码的运行结果如下: 第四种形式:
vector (const vector& x);
这个就是拷贝构造,创建一个对象的时候将另外一个对象的内容初始化给新创建的对象,比如说下面的代码:
void test4()
{
vector v1;
v1.push_back(Date(2018, 11, 11));
v1.push_back(Date(2019, 11, 11));
v1.push_back(Date(2020, 11, 11));
v1.push_back(Date(2021, 11, 11));
v1.push_back(Date(2022, 11, 11));
vectorv2(v1);
for (auto v : v2)
{
v.print();
}
}
这段代码的运行结果为: 那么这就是构造函数的四种不同的形式希望大家能够理解。
reserve
当我们要往一个对象中插入许多数据时,对象会不停的进行扩容,而对象里面的扩容基本上都是异地扩容,所以当对象不停进行扩容的话,他的效率必定会降低很多,所以为了避免扩容我们这里就可以使用reserve函数来一次性提高对象的容量,该函数的形式如下: 我们可以用下面的代码来看看这个函数的使用:
void test5()
{
vector v1(5);
cout
ch.print();
}
}
代码的运行结果为: ![在这里插入图片描述](https://img-blog.csdnimg.cn/183455cb13dc465c9ee900e5023200d3.png)
insert
上面的函数只能在对象的尾部进行插入数据,并且每使用一次这个函数只能插入一个数据,那这里的insert函数则可以实现在对象的任意位置插入数据,并且一下子可以插入多个数据该函数的形式如下: 这里的position是插入的位置,const value_type& val 是你要插入的数据,参数n的作用就是插入n个数据,最后一种形式就是通过迭代器将数据插入,我们可以通过下面的代码测试一下三种不同的插入:
void test7()
{
vector v;
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
cout
ch.print();
}
v2.insert(it2,3, Date(2018, 18, 18));
cout
ch.print();
}
}
代码的运行结果如下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/4e2f8826a59244dfb78af466271aa23c.png)
resize
这个函数也能往对象里面添加内容,但是这个函数的主要功能是修改对象的长度,当你修改的长度小于原本的长度的时候,resize会删除多余的数据,当你给的长度大于原本长度的时候,该函数会将多出来内容填充成你给的数据或者该类型的默认构造,我们来看看该函数的介绍: 我们可以看看下面的代码来分析两种不同的情况,第一种当给的长度大于原本长度的时候:
void test8()
{
vector v;
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
cout
ch.print();
}
}
这段代码的运行结果为: 我们可以看到当长度变大之后resize会自动的将多出来的内存填补上去,这里多出来了三个所以就填补了三个,而我们没有传对应的值所以这里用的就Date的默认构造来进行填补,我们再来看看第二种情况:当修改的长度小于原本的长度的时候:
void test8()
{
vector v;
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
cout
ch.print();
}
cout
vector v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout
ch.print();
}
cout
ch.print();
}
cout
vector v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout
ch.print();
}
v.pop_back();
cout
vector v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout
ch.print();
}
}
我们将这个代码运行一下就可以看到第三个元素被删除了: 其次就是一段元素的删除:
void test11()
{
vector v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout
ch.print();
}
}
这里是一段数据的删除,这里的一段所表示的意思就是将第一个元素和最后一个元素保留其他元素都删除,我们可以看看这段代码的运行结果: 这就是该函数的使用希望大家能够理解。
clear
上面是一段数据或者一个数据的删除,那么这里的clear函数是将全部的数据删除,我们可以看看这个函数的介绍: 这个函数的使用也非常的简单毕竟他没有参数嘛,我们可以看看下面的代码来看看这个函数的作用:
void test11()
{
vector v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout
ch.print();
}
cout
vector v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout
vector v;
v.reserve(10);
cout
vector v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout
ch.print();
}
}
代码的运行结果如下:
当我们给的下标不合法的时候再使用[ ]就会报错:
void test13()
{
vector v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout
ch.print();
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/50e4e6a276a740c59ea3caccf6c38e5a.png)
at
这个函数的作用和operator[ ]的作用是一样的,唯一的区别就在于对于不合法的下标at会抛异常不会报错而[ ]会报错,我们来看看这个函数的介绍: 我们来看看下面的代码:
void test14()
{
vector v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout
ch.print();
}
}
这段代码的运行结果如下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/4de0f34120ce4b8896b7f5c33b5a988e.png)
front
该函数的作用就是返回vector中的第一个元素,我们可以根据这个函数来修改和打印对应的数据。
back
该函数的作用就是返回vector中的最后一个元素,我们可以根据这个函数来修改和打印对应的数据。 我们可以通过下面的代码来看看上面两个函数的使用:
void test15()
{
vector v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
v.front().print();
v.back().print();
v.front() = Date(2018, 18, 18);
v.back() = Date(2023, 1, 1);
v.front().print();
v.back().print();
}
代码的运行结果如下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/544a400592504e768a598b6074488c72.png)
vector其他函数
operator=
这个就是赋值重载,将一个vector对象的内容赋值给另一个vector对象,我们可以看看该函数的介绍: 该函数的使用如下:
void test16()
{
vector v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
vector v1;
v1 = v;
for (auto ch : v1)
{
ch.print();
}
}
代码的运行结果如下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/4df16658e6754a0aa4f80e3c190db5d5.png)
swap
在vector对象当中有两个swap函数,我们来看看这两个不同的swap函数对应的介绍: 第二个: 而且在我们的库中也有一个swap函数: 那这里有两个问题,为什么库中会有两个swap函数?为什么算法库中提供了swap函数,在vector中还要自己写swap函数呢?原因很简单,库中提供的swap函数的实现方法会造成三次深拷贝,这样的话会导致效率降低,所以我们vector就自己提供了一个swap函数,那为什么要写两个呢?答案也很简单因为有些使用使用着容易把swap函数的形式写错,如果是这样的话: 我们调用swap函数应该是这样:
std::vector foo (3,100);
std::vector bar (5,200);
foo.swap(bar);
而很多小伙伴会写成这样:
swap(foo,bar);
这样写的话调用的就是算法库中的swap所以为了防止有小伙伴写错了形式而调用了效率更低的swap我们的库就给了一个形式 这样的话就算你写错了,调用得分也是效率更高的swap。
|