创作初心:在加深个人对知识系统理解的同时希望可以帮助到更多需要的同学
🛠️柯一梦主页详情
座右铭:心向深耕,不问阶序;汗沃其根,花自满枝。
目录
在今天vector的学习之前我们先讲解几个知识:
1.initializer_list
我们可以看到c++11里面vector的构造函数的一个参数是initializer_list,这个参数的作用是什么呢?
initializer_list是一个包装了"编译器临时数组"的轻量级只读对象(这个对象里面有一些成员函数begin,end之类的,并且是用const修饰过了之后的),既然是"数组",我们在初始化一些容器的时候就可以用{},传入多个值对容器进行初始化。它的底层原理是:在栈上开辟一个只读的空间,然后vector再主动的去读取initializer_list里面的内容,并且拷贝到自己的容器里。(注意:所以我们在使用{}初始化一个vector对象的时候,本质上就是直接初始化(这里又有小伙伴疑惑了,为什么这里不是隐式类型转换呢?其实如果我们的赋值方式是v{1,2,3},这里编译器会直接把{1,2,3}当成initializer去构造,但是如果是v={1,2,3},这里就涉及到了隐式类型转换,也就是先构造一个函数,然后再进行拷贝构造))
int main()
{
vector<int> v1{ 1,2,3,4,5,6,7,8,9,10 };
for (const auto& e : v1)
{
cout << e << " ";
}
return 0;
}
2.emplace_back:

emplace_back和push_back有什么区别呢?我们来看下面这段代码
int main()
{
struct A//我们先定义一个类
{
A(int a1,int a2)
:_a1(a1)
,_a2(a2)
{
}
A(const A& a)
{
}
int _a1;
int _a2;
};
vector<A> v1;
//我们先使用push_back实现以下三个东西
//1.传入构造好的对象
A a(1,2);
v1.push_back(a);
//2.传入匿名对象
v1.push_back(A(1, 2));
//3.多参数构造函数的隐式类型转换需要用{}括起来
v1.push_back({ 1,2 });
//我们再使用emplace_back实现一下:
//1.传入构造好的对象
A a(1, 2);
v1.emplace_back(a);
//2.传入匿名对象
v1.emplace_back(A(1, 2));
//3.不需要使用{}进行隐式类型转换
v1.emplace_back(1,2);//因为他是模版的可变参数,所以可以直接传过去
return 0;
}

3.使用for循环打印多参数的自定义类型对象
3.1迭代器遍历v1
int main()
{
struct A//我们先定义一个类
{
A(int a1, int a2)
:_a1(a1)
, _a2(a2)
{
}
A(const A& a)
:_a1(a._a1)
, _a2(a._a2)
{
}
int _a1;
int _a2;
};
vector<A> v1;
//我们先使用push_back实现以下三个东西
//1.传入构造好的对象
A a1(1, 2);
v1.push_back(a1);
//2.传入匿名对象
v1.push_back(A(1, 2));
//3.多参数构造函数的隐式类型转换需要用{}括起来
v1.push_back({ 1,2 });
//我们再使用emplace_back实现一下:
//1.传入构造好的对象
A a2(1, 2);
v1.emplace_back(a2);
//2.传入匿名对象
v1.emplace_back(A(1, 2));
//3.不需要使用{}进行隐式类型转换
v1.emplace_back(1, 2);//因为他是模版的可变参数,所以可以直接传过去
//1.iterator访问v1
vector<A>::iterator it1 = v1.begin();
while(it1!=v1.end())
{
cout << (*it1)._a1 << " " << (*it1)._a2 << endl;
++it1;
}
return 0;
}
我刚才在写迭代器遍历v1的内容的时候出现了一些问题,我刚才写的是一个空的构造函数,vector的push_back插入的是拷贝对象而不是对象本身,所以我们子啊使用push_back的时候要把自定义类型的拷贝构造先写好。
3.2for循环遍历
//C++13的遍历方式
for (const auto& aa : v1)
{
cout << aa._a1 << " " << aa._a2 << endl;//我们这里的本来就是对象,所以不能使用->
}
//C++17的遍历方式,结构化绑定
for (auto [x, y] : v1)
{
cout << x << " " << y << endl;
}
return 0;

4.leetcode训练题,写一个杨辉三角
4.1使用C语言
先讲一下做题思路:我们要先构造出来一个二维数组,然后再去构造一维数组,紧接着就是给一维数组里面的各个地址赋值。在赋值的时候我们要先将每个一维数组的头尾进行赋值,然后再让每一行的元素=上一行该位置与前一个位置元素的和
int** generate(int numRows, int* returnSize, int** returnColumnSizes) {
int** aa = (int**)malloc(sizeof(int*)*numRows);
*returnColumnSizes = (int*)malloc(sizeof(int)*numRows);
for(int i = 0;i<numRows;i++)
{
(*returnColumnSizes)[i] = i+1;
aa[i] = (int*)malloc(sizeof(int)*(i+1));
}
for(int i = 0;i<numRows;i++)
{
aa[i][0] = 1;
aa[i][i] = 1;
for(int j = 1;j<i;j++)
{
aa[i][j] = aa[i-1][j]+aa[i-1][j-1];
}
}
*returnSize = numRows;
return aa;
}
4.2使用C++
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> aa;
aa.resize(numRows,vector<int>());
for(size_t num = 0;num<numRows;++num)
{
aa[num].resize(num+1,1);
}
for(size_t i = 2;i<aa.size();++i)
{
for(size_t j = 1;j<aa[i].size()-1;++j)
{
aa[i][j] = (aa[i-1][j])+(aa[i-1][j-1]);
}
}
return aa;
}
};
5.迭代器失效
vector的insert和erase的使用都会牵扯到迭代器,这里面有一个隐形的炸弹就是迭代器失效
实例1:
insert:
#include<initializer_list> #include<iostream> #include<vector>//包含vector #include<algorithm>//包含find void test2() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); //在2的位置插入一个10 vector<int>::iterator pos = find(v.begin(), v.end(), 2); v.insert(pos,10); v.erase(pos); for (auto& e : v) { cout << e << " "; } } int main() { test2(); return 0; }这块代码会直接报错,因为vs2022编译器会直接终止这种违法行为。有的同学问为什么会违法呢?其实我们在insert的时候,v的空间可能会涉及到扩容的问题,一旦涉及扩容,先前指向的空间就会被释放,pos也就变成了野指针。
实例2
erase:
#include<initializer_list> #include<iostream> #include<vector>//包含vector #include<algorithm>//包含find void test2() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); v.push_back(7); v.push_back(8); v.push_back(9); v.push_back(10); //在2的位置插入一个10 vector<int>::iterator it = v.begin(); while (it != v.end()) { if ((*it) / 2 == 0) { v.erase(it); ++it; } } }类似于insert,这个erase使用过的it迭代器依旧报错了
解决方法:我们再使用erase或者insert的时候,我们都要对迭代器进行重新赋值(erase和insert函数都有返回值,返回值就是迭代器)!!!

