vector是表示可变大小数组的序列容器。
平时只关注第一个参数就行,第一个参数要考虑决定了vector里面存什么类型数组。第二个参数是空间配置器,即内存池。
第一个是全缺省构造函数。第二第三是使用迭代器构造,第四个是拷贝构造。
下面用vector和迭代器试一下。
#include<iostream> #include<vector> using namespace std; void test1() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); for (int i = 0;i < v.size();i++) { cout << v[i]<<' '; } cout << endl; vector <int>::iterator it = v.begin(); while (it != v.end()) { cout << *it<<' '; it++; } cout << endl; } int main() { test1(); return 0; }
问题:底下这两个有没有区别? 它俩都是char形数组,能不能用vector代替string?

有区别:
- string后面有斜杠0。
- string支持用ASCII比较大小。而vector不支持,因为class T参数是个范型,不一定是char。
- 他俩接口不一样,sring可以+=,可以+=字符或字符串,vector没有必要也没有+=。
vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); cout << v.capacity() << endl; v.reserve(10); cout << v.capacity() << endl; v.reserve(6); cout << v.capacity() << endl;
![]()
不会缩容,比当前容量小时,不缩容,以空间换时间。
不能只退回一部分空间,可以用一个malloc开辟的空间不能free两次理解。


![]()
这里面的int就是下面的T,就是这个类型,val就是value_type这个类型的数据。val是要补的数据。

如果只写v.resize(8),那么第二个参数缺省值是什么呢?
value_type()相当于T(),如果是自定义类型,相当于调用它的构造函数。如果是内置类型,也可以拿构造函数理解。
那value_type()能不能改成0呢?
不能,因为一些类型不能直接用0初始化,比如日期类。
- 下面代码实现一下
void test2() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.resize(8); for (int i = 0;i < v.size();i++) { cout << v[i] << ' '; } cout << endl; v.resize(10, 2); for (int i = 0;i < v.size();i++) { cout << v[i] << ' '; } cout << endl; v.resize(3); for (int i = 0;i < v.size();i++) { cout << v[i] << ' '; } cout << endl; }
- 下面看一下vector是如何扩容的。
void test3() { vector<int> v; int sz = v.capacity(); for (int i = 0;i < 100;i++) { v.push_back(i); if (sz != v.capacity()) { sz = v.capacity(); cout << "capacity changed:" << sz << endl; } } }
VS2019大约是1.5倍扩容。
Linux上是2倍扩容。
为什么一般是扩2倍?
因为2倍通常比较合适,如果扩少了,会导致频繁扩容,扩多了,会造成空间浪费。
如果不断扩容,后面不一定有足够空间原地扩容,所以可以用reserve先申请空间。
构造时开空间也可以,但没有reserve灵活。
力扣
https://leetcode-cn.com/problems/pascals-triangle/description/ (杨辉三角链接)

class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> vv;
vv.resize(numRows);
for(int i=0;i<numRows;i++)
{
vv[i].resize(i+1,0);
vv[i][0]=vv[i][i]=1;
}
for(int i=0;i<numRows;i++)
{
for(int j=0;j<i+1;j++)
{
if(vv[i][j]==0)
{
vv[i][j]=vv[i-1][j-1]+vv[i-1][j];
}
}
}
return vv;
}
};
reserve和resize是string和vector独有的。
比如list它俩没有意义。
这两个是同一个size(),只不过上面的是权限平移,下面是权限缩小。


但operator[]是有两个版本的。
改不了。 出现错误。

改得了。

只读接口函数,只提供const就可以,如果只写的接口函数(push_back),必须提供非const,可读可写的接口函数,就需要提供const和非const接口(operator[])。
at可读性不强。at是成员函数,operator[]是运算符重载。
- 它和operator还有没有区别?
- 它俩在访问下标大于v.resize时,at会抛异常,而operator[]会断言报错。

[]用断言检查里面数字是否小于size。
此程序报错

断言检查

operator[]加了个断言检查不能让i大于v.size()。这是规定。
可以这么用,用push_back

at这么写报错,其实是报异常,其实异常能被捕获。

这样可以捕获异常

断言比较暴力,直接终止程序。
断言缺点是,release版本不起作用。
assign是个赋值,它不是用对象赋值,而是靠需求赋值。比如用n个对象赋值,

之前的值被覆盖。

vector支持传迭代器。

它其实是个模板。

因为v是<int>,所以它取的是ASCII码

迭代器的加减


string的insert大部分这个参数是下标,而vector是迭代器。

数据结构核心的部分是增删查改,
vector
![]()
想要在第二个位置头插可以移动迭代器。
因为vector是连续空间,所以加2可以指向第3个字符位置

vector没有自己的find函数,用的是std中的。

体现了迭代器区间左闭右开的重要性,因为last不是成员值,失败可以返回last。
例子

因为string更多的是要找子串,所以string里面自己有一个find。
string中的find返回的是下标。

左闭右开。

![]()
![]()
clear不会影响capacity。只会清空数据。
为什么vector有专门swap?

因为我有时会这样用
![]()
这样如果vector没有的话,就会走到算法库里面的swap,算法库里面的swap要进行深拷贝,会降低效率。
为了避免这种情况,vector自己有一个swap。
缩容函数。以空间换时间,c++11提供,这个要少用。
![]()
不允许在原先空间处只释放一部分内存。不允许分段释放,只能整体释放。
所以下面这样不会缩容。
设计理念就是不动空间,不缩容。空间换时间。
缩容一般是开辟一个新空间,释放旧空间。
所以这个就是个反面函数。
当我们确定较大空间我们不需要时,会选择这个函数。
stl3.0源码网盘链接
提取码:0s5t




VS2019大约是1.5倍扩容。








2367

被折叠的 条评论
为什么被折叠?



