种一棵树最好的时间是十年前,其次是现在。
文章目录
前言
在C++创建数组时需要提前分配好大小,但是vector可以解决这个问题,大小用nums.size()表示即可。使用起来特别简便。我对学到的一维数组和二维数组的相关知识点做了总结,还有几道题目(为了避免篇幅太长,放在下一篇里单独说)。
头文件:#include<vector>,而且要加using namespace std;
一、一维数组
1、创建
vector<int>nums;//创建整型一维数组
vector<int>nums(n);//指定长度为n
vector<int>nums(5,3);//创建[3 3 3 3 3]
2、添加元素、赋值
nums.push_back(a);//在数组末尾添加a
num[i]=2;//直接赋值
vector<int>nums1;
nums1=nums;//可以整体赋值
3、删除元素
nums.resize(nums.size()-i);//减少i个元素
nums.pop_back();//括号里面不用加东西,删除最后一个元素
4、长度相关
nums.size();//数组的长度
cout << nums[0] << endl;//输出第一个元素
cout << nums[nums.size()-1] << endl;//输出最后一个元素
nums.resize(m);//长度改为m
5、是否空&清空
nums.empty() //判断是否空
nums.clear() //清空
6、排序&翻转&合并
#include<algothrim>
sort(nums.begin(),nums.end());//从小到大排序
sort(nums.begin(),nums.begin()+3);//排序前面三个数
reverse(nums.begin(),nums.end());//翻转
//将nums1和nums2合并
vector<int>nums1(m),nums2(n);
vector<int>nums;
nums.resize(m+n);
merge(nums1.begin(),nums1.end(),nums2.begin(),nums2.end(),nums);
7、vector数据类型可以自定义
struct Stu{
string name;
int score;
};
int main()
{
vector<Stu>vec;
//创建a再赋值
Stu a;
a.name="abc";
a.score=100;
vec.push_back(a);
//直接赋值
vec.push_back({"acb",90});
}
二、二维数组
1、初始化
方法一:创建&直接初始化
vector<vector<int>>nums;//创建数组
vector<vector<int> >nums;//有人说必须打空格,但是我不打空格好像也没事
vector<vector<int>>nums(3);//创建三行的数组
vector<vector<int>>nums(3,vector<int>(5,0)); //创建三行五列的数组,初始值为0
方法二:用resize构建
下面定义的是行为r(row),列为c(column)的二维数组,初始值为0(因为resize默认为0)。
vector<vector<int>> new_mat(r);//注意这个r是不可缺少的,规定其有多少行
for(int i=0 ;i<r; i++) //二维vector的初始化时有要求的
{
new_mat[i].resize(c);
}
2、添加元素
场景1:插入的是一个数组
vector<vector<int>>A;
vector<int>B;
B.push_back(0);
B.push_back(1);
A.push_back(B);
B.clear();
B.push_back(3);
B.push_back(4);
A.push_back(B);
场景2:每行不一定几个数,就是想对每行的列进行操作,且插入的是元素
每一行的元素个数可以不相同!!!在声明时,行数一定要有!!然后push_back就可以了!
vector<vector<int>>mat(r);//每行的定义
mat[i].push_back(1);//这就是该第i-1行的插入一个元素,值为1
别人写的杨辉三角:
vector<vector<int>> generate(int numRows) {
vector<vector<int>>mat(numRows);
vector<int> tem;
tem.reserve(1000);
for(int i=0;i<numRows;i++)
{
for(int j=0;j<i+1;j++)
{
if((j==0)||(j==i))mat[i].push_back(1);
else
{
int value = tem[j-1]+tem[j];
mat[i].push_back(value);
}
}
tem.clear();//一维数组只清除里面的元素,而不对容量做操作。
for(auto it=mat[i].begin();it!=mat[i].end();it++)
{
tem.push_back(*it);
}
}
3、长度获取
m=A.size();//row
n=A[0].size();//column
4、赋值
A[0][0]=4;
A.push_back({ 1,1 });//这样[1,1]就进入A数组了
5、输出
auto it = a.begin();
a.erase(++it);//删除第一行
auto it2 = it.begin();
a[0].erase(++it2);//删除第一行的第一列,注意0不要忘记
其中,it2也可直接定义,而不去依靠it。
for(auto it2=mat[i].begin();it2!=mat[i].end();it2++)
{
tem.push_back(*it2);
}
6、遍历&迭代器赋值
//遍历
for (auto it = new_mat.begin(); it != new_mat.end(); it++)
{
for (auto it2 = it->begin(); it2 != it->end(); it2++)
{
cout << "[" << *it2 << "]";
}
cout << endl;
}
//迭代器赋值
for(auto it=ans.begin();it!=ans.end();it++)
{
if(key == (*it)[0]) (*it)[1]=value;//注意括号是要把整个*it括起来的!
}
7、删除(乏了乏了,直接复制别人写的)
首先先说本方法,用STL成员函数的,例如删除2
for(auto it=ans.begin();it!=ans.end();it++)
{
if((*it)[0] == 2) it = ans.erase(it);//注意erase里面是要放迭代器的
if(it == ans.end()) break;//这一步是要防止当删除的元素为最后一个,导致it++直接爆炸
}
可以看到,上面又是必须迭代器,又是要加一步检查,那如何更好地快速处理呢?以一维为例!!(erase和remove结合即可):
ans.erase(remove(ans.begin(), ans.end(), 2), ans.end());
remove是algorithm库中地函数,并不是真正地删除,而是以覆盖的方式将满足删除条件的元素移到容器最后(其实就是想调用函数找到迭代器)。然后我们删除erase最后的元素即可快速删除。那么对于二维来说呢(例如我要删除二维中第一个元素为2的数组)可以看到,并不简单。
for(auto it=ans.begin();it!=ans.end();it++)
{
if(key == (*it)[0]) ans.erase(std::remove(ans.begin(),ans.end(),*it),ans.end());
if(it == ans.end()) break;
}
三、出现的问题
使用动态数组时会产生问题:(虽然我也没遇到过,不过记录下来万一用到了嘞)
1、在处理小数据时是没问题的,但处理大数据时,vector在重新分配发生时一般会把容量(所分配好的内存空间)翻倍,这将导致出现大量的冗余空间。
2、在对二维数组创建时,会出现创建失败的情况,如下就会报错:
vector<vector<int>>nums;
nums[0].push_back(1);
cout << nums[0][0];
首先要明白,我们第二个问题的出现,其实就是因为第一个问题,那么我们逐个分析一下:
对vector的.size()代表时查找里面有多少个数,而.capacity()是查询他的容量(最多放多少个数)。因此我们有两个方法来解决:
1、resize(Container::size_type n)强制把容器改为容纳n个元素。调用resize之后,size将会返回n。如果n小于当前大小,容器尾部的元素会被销毁。如果n大于当前大小,新默认构造的元素会添加到容器尾部。如果n大于当前容量,在元素加入之前会发生重新分配。
2、reserve(Container::size_type n)强制容器把它的容量改为至少n,提供的n不小于当前大小。这一般强迫进行一次重新分配,因为容量需要增加。(如果n小于当前容量,vector忽略它,这个调用什么都不做,string可能把它的容量减少为size()和n中大的数,但string的大小没有改变。
【小结】上述两方法的区别
1、reserve表示容器预留空间,但并不是真正的创建对象,需要通过insert()或push_back()等创建对象。resize既分配了空间,也创建了对象。
2、reserve只修改capacity大小,不修改size大小,resize既修改capacity大小,也修改size大小。
3、resize带两个参数,一个表示容器大小,一个表示初始值(默认为0)。reserve只带一个参数,表示容器预留的大小。
因此,我们在对一维数组push前,可以来一个reverse,这样在不断push的过程中就不会发生重新分配了。如:vector<int> a; a.reserve(1000);
阐述一下第二个问题出现的原因:vector直接根据下标访问必须要先push,存在数才行。而上面想直接对第一行里面的各个元素进行访问修改时绝对不行的。但是相反,如果我们先对第一行进行赋值,然后再访问,这样又是可以的,如:
vector<vector<int>> a;
vector<int> b;
b.push_back(1);
a.push_back(b);//相当于增加二维数组中的行
cout << a[0][0];
第一次写博客,若有错误欢迎指正,如果有版权问题请及时与我联系修改删除,感谢感谢!!!
参考的博主:
1、https://blog.csdn.net/jackywgw/article/details/6248342
2、https://blog.csdn.net/liuweiyuxiang/article/details/88692708
3、https://blog.csdn.net/qq_38289815/article/details/106052582
4、https://blog.csdn.net/qq_31918961/article/details/90109988
5、https://blog.csdn.net/m0_57298796/article/details/123952640