STL2--vector的介绍以及使用

创作初心:在加深个人对知识系统理解的同时希望可以帮助到更多需要的同学

😄柯一梦的专栏系列

🚀柯一梦的Gitee主页

🛠️柯一梦主页详情

座右铭:心向深耕,不问阶序;汗沃其根,花自满枝。


目录

1.initializer_list

​编辑

2.emplace_back:

3.使用for循环打印多参数的自定义类型对象

3.1迭代器遍历v1

3.2for循环遍历

4.leetcode训练题,写一个杨辉三角

4.1使用C语言

4.2使用C++

5.迭代器失效


在今天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函数都有返回值,返回值就是迭代器)!!!


相关推荐
Beginner x_u2 小时前
JavaScript 中浅拷贝与深拷贝的差异与实现方式整理
开发语言·javascript·浅拷贝·深拷贝
txinyu的博客2 小时前
解析muduo源码之 EPollPoller.h & EPollPoller.cc
c++
云霄IT2 小时前
go语言post请求遭遇403反爬解决tls/ja3指纹或Cloudflare防护
开发语言·后端·golang
自动化控制仿真经验汇总2 小时前
电子抑振控制实验中MATLAB+示波器的用法-PART-RIGOL-电磁制振
开发语言·matlab
凯子坚持 c2 小时前
C++基于微服务脚手架的视频点播系统---客户端(3)
开发语言·c++·微服务
代码方舟2 小时前
Java后端实战:对接天远车辆过户查询API打造自动化车况评估系统
java·开发语言·自动化
麒qiqi2 小时前
从 C 基础到 ARM Linux 驱动开发:嵌入式开发核心知识点全解析
java·开发语言
寻寻觅觅☆2 小时前
东华OJ-基础题-86-字符串统计(C++)
开发语言·c++·算法
楼田莉子2 小时前
Linux学习:进程信号
linux·运维·服务器·c++·学习