【C++ STL】vector详解

Ⅰ、vector是什么?

1、vector的定义

vector的中文意思是向量的意思,说人话就是一个顺序表,他本身也是一个数组,但有人有疑问string不也是顺序表吗?为什么还需要vector,因为string只能存char类型的对于其他类型不能存储,还有一点是对于字符的顺序表有很多单独的接口需要实现但对于其他类型的顺序表并不太需要这就会导致把string并入vector不太合适所以他们两是分开的。下面是文档对于vector的介绍。

2、用vector怎么去实现二维数组?

为什么vector可以去实现二维数组?原因是vector是类模板template<class T>这里的T可以是任何类型,string,vector<T>,list<T>等等都是可以的,那么vector<vector<list>>是什么样的呢?

如何去随机去访问数据呢?这里也是如何通过下标访问的讲解。

通过两个方括号的方式就可以去实现,vector重载了operator[]和operator*,我们知道数组a[ i ] ==         *(a+i),这里也是一样的a1[ 1] == *(a1 + 1)解引用后*(a1 + 1)是vector[int]类型的,*(a1 + 1)[2] == *((a1+1)+2),类型就是int。通过这种方式就可以去随机遍历数据了。

Ⅱ、vector的构造函数

vector用来模板来进行实现提高了代码的复用,我们先看一下他的成员变量,下面我将展示一段源码这里展示了vector的成员变量。在源码中选择用了三个迭代器去控制vector

在这里我们着重讲解一下iterator实现的迭代器。

1、用iterator构造

可以给任何容器一段迭代器区间去构造vector。要注意一定要加<>里面要写类型,因为类模板一定要显示实例化

void test_vector()
{
	vector<int>a1;
	a1.push_back(1);
	a1.push_back(2);
	a1.push_back(3);
	a1.push_back(4);
	a1.push_back(5);
	a1.push_back(6);
	vector<int> a2(a1.begin(), a1.end());
	print_container(a2);
}
int main()
{
	test_vector();
	return 0;
}
2、用initializer_list构造
void test2_vector()
{
    vector<int>a1 = { 1,2,3,4,5,6 };
    print_container(a1);
}
int main()
{
    test2_vector();
    return 0;
}

这里initializer_list是一个类型可以用于接收花括号初始化列表,写成vector<int>a1 ={1,2,3,4,5,6}的形式相当于一种隐式类型转换,{1,2,3,4,5,6}先生成一个vector<int>类型的临时变量再去拷贝构造,因为单参数的构造函数支持类型转换可以把initializer_list构造生成vector<int>,如果写成vector<int>a2({1,2,3,4,5,6})这种是直接构造调用 vector (initializer_list<value_type> il, const allocator_type& alloc = allocator_type()) 这个构造函数去构造vector<int>。对于initializer_list我会在list里更加详细的讲解。

Ⅲ、vector的迭代器

vector的迭代器实现依旧是采用了原生指针的方法,只不过在源代码中又对它进行了一层封装,vector它的结构很好是一块连续存储的空间它可以做到时间复杂度O(1)的随机访问和修改,也可以做到O(1)的尾删,但对于中间位置和头部位置的插入和删除是时间复杂度O(n)对效率的影响较大使用在使用时要注意!

这里的迭代器和string的迭代器基本上差不多 ,如果不太明白可以看C++中的String的常用函数用法总结和模拟实现-优快云博客这篇文章,这里我就简单的画一下rend/rbegin和begin/end这两组迭代器的图帮助大家理解一下。

Ⅳ、vector常用函数实例解析

1、size()

size就是返回有效数据的个数。比较简单,直接对象.size()就可以了。

2、 resize(size_type n) / resize (size_type n, const T & val)

resize得分两种情况分析,一是当n < size()的情况,它会改变_finish的位置从而减少数据个数。二是当 n > size()的情况,如果capacity不足它会调用reserve()去扩大空间,再填充val直到size() == n。 

记得第一个参数是要调整的个数第二个值是当要填充时放的数据。

3、push_back

push_back()的时间复杂度是O(1),当面对_finish == _end_of_storage时先进行扩容再进行push,当_finish != _end_of_storage 的时候就可以直接插入进去。

4、 insert

支持在任意位置前面插入数据,但会挪动数据向后所以它的时间复杂度是O(N),使用insert要注意迭代器失效的情况。比如下面这种情况

这里为什么报错,可能大家看到这里不太清楚再看下面这张图大家应该会清楚一点。

这里的原因是当insert了以后it1及其后面的迭代器(如第二张图片的it2)都会已经失效了如果这时候还使用它就会报错,(这里我想强调一下也不是每一个编译器都会报错,再Linux下的gcc就不会报错,这里是因为vs在这里强制检测如果没有更新迭代器就会报错),这里的报错是应该的因为如果insert的时候空间不够要去扩容 it1 这个迭代器就会指向一个已经释放的空间这将会造成很大的问题(有点像野指针的情况),所以这里vs选择去检查无论insert的时候扩不扩容只要不更新都报错。一定要记得要更新迭代器以后再去使用像第一张图片一样。

还要再声明一下,insert会返回一个迭代器,这个迭代器指向的位置是刚刚插入的数据,如下面这张图

5、erase

erase支持删除一个数据和删除一整个迭代器区间,当然 erase也有迭代器失效的情况,下面这个张图是erase的函数重载。

下面是对删除一个和一段迭代器区间的使用:

 

要注意这里的迭代器区间 是左闭右开区间 [ first , last )。

接下来我们看一下erase迭代器失效的情况。

这里的原因也是erase以后后面的迭代器全部失效,vs会检查如果不更新使用会报错,这里的本质是erase删除以后这个it会指向其他数据从而失效,(erase会返回一个迭代器指向被删除数据的下一个位置,这个也相当于变相的++),这个在vs2019中展示比较好在vs2022这个都会报错在vs2019中上面这段代码还是可以被编译通过的但效果并不是我们期待的那样。

文章到此结束,如果有疑问的小伙伴可以在评论区提问记得一键三连哦~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值