经历的近一年的学习,终于算是想起来了还有这个博客,那终于开始重新拾起,进行一个stl的学习
标准模板库
在C++标准库中,只需要#include头文件,便可以引用
STL标准库分为几个大类,这篇文章只简要介绍vector
vector
什么是vector?我们可以把vector简单的理解为是一个比unsigned long long
还要更大的数组,但这并不意味着他占用的空间会很大,事实上,vector数组的大小是在变化着的,这取决于你给他塞入的数据大小。
要使用vector类型,我们需要以下头文件
#include<vector>
vector的定义
vector遵循以下的方式定义:
vector<数据类型> 变量名
数据类型除了常见的int
,float
,double
,long
以及long long
,ull
之外,还可以是STL容器类型如vector
,queue
,set
:
vector<int> a;
vector<double> a;
vector<string> a;
vector<long long> a;
vector<vector<int> > a;
vector本身就可以视为一个一维数组,如果在这基础上再开数组,那就是一个二维数组
如:
vector<int > a[n];
访问vector
vector的访问如同数组一般,直接使用下标即可访问:
#include<vector>
int mian()
{
std::vector<int > a;//定义vector
a.push_back(114514);//向vector中插入114514;
cout<<a[0];//访问,输出a[0]=1;
}
输出如下:
114514
同时,stl非常酷炫的一点在于,他有着自己独特的访问方法——迭代器(iterator)
迭代器的使用方法如同指针一样:
vector<类型名>::iterator 变量名;
例子也很好理解:
vector<int >::iterator itera;
但由于本人不是很会使用迭代器,故先放置一边
vector的常见函数
在stl中,常见的函数有以下几个:
- .push_back();
- .pop.back();
- .size();
- .clear();
- .insert();
- .erase();
push_back()
push_back()
的意思非常好理解,他事实上就是把向vector中插入一个元素到vector的末尾
int n,x;
vector<int > a;
for(int i=1;i<=n;i++)
{
a.push_back(x);//把n插入数组
}
pop_back()
pop_back()
这个操作可以理解为push_back()
的反面,即将一个元素从vector中弹出
int n,x;
vector<int > a;
for(int i=1;i<=n;i++)
{
a.push_back(x);
cout<<a[i]<<" ";
}
cout<<endl;
a.pop_back();
for(int i=1;i<=n;i++)
{
cout<<a[i]<<" ";
}
假设输入为:
1 2 3 4 5
操作后是:
1 2 3 4 5//原本的数列
、1 2 3 4 //pop之后的数列
size()
这个函数顾名思义,就是查询现在vector的大小(所含元素的个数)
int n,x;
vector<int > a;
for(int i=1;i<=n;i++)
{
a.push_back(x);//把n插入数组
}
cout<<a.size()<<endl;//输出vector大小
假设输入为:
1 2 3 4 6
输出为:
5
clear()
clear()
的作用主要是一键清除vector中的所有元素(全杀了)
int n,x;
vector<int > a;
for(int i=1;i<=n;i++)
{
a.push_back(x);
cout<<a[i]<<" ";
}
cout<<endl;
a.clear();
for(int i=1;i<=n;i++)
{
cout<<a[i]<<" ";
}
假设输入为:
1 2 3 4 5
将不会输出任何东西,因为这个vector已经被清空了
insert
insert(需要插入的位置,需要插入的元素)
与push_back()
不同的地方是,他没有push_back()
那么粗暴无脑的往最后面插入元素,他是先选择vector中的一个位置,在这个位置插入元素
int n,x;
vector<int > a;
for(int i=1;i<=n;i++)
{
a.push_back(x);
cout<<a[i]<<" ";
}
cout<<endl;
insert(a.begin()+3,1919810)//将1919810插入到数列的第3位
for(int i=1;i<=n;i++)
{
cout<<a[i]<<" ";
}
假设输入为:
1 2 3 4 5 6
输出为:
1 2 1919810 3 4 5 6
erase()
正如push_back()
有一个反义词叫pop_back()
,insert()
也有自己对应的反义词erase()
,他的作用是用来删去指定位置的元素
erase不止可以删除一个元素,也可以删除一个区间的元素
删除一个元素:
erase(元素);
删除一个区间的元素:
erase(左区间,右区间);
注意:这里的区间是左闭右开的
这样便能删除这个区间的元素
vector的常见用途
1.vector用来储存数据的优势在于,他的数组大小是动态变化的,可以较高效的节省空间
2.邻接表存图
vector练习题与解析
题目描述
给定 \(n\) 条数据,第 \(i\) 条数据有 \(s_i\) 个数,依次记为 \(a_{i, 1}, a_{i, 2}, \dots a_{i, s_i}\)。
现在有 \(q\) 次询问,每次询问第 \(x\) 条数据的第 \(y\) 个数,即 \(a_{x,y}\) 是多少。
为了避免输出过大,你只需要输出所有询问的答案的按位异或和。
按位异或指的是 C++ 中的「^」运算符。你可以参考「说明/提示」中的代码求出若干个数的按位异或和。
输入格式
第一行是两个整数,表示数据条数 \(n\) 和询问次数 \(q\)。
接下来 \(n\) 行,每行依次表示一条数据,每行首先是一个整数,表示本条数据的数字个数 \(s_i\),接下来 \(s_i\) 个整数,依次表示本条数据的每个数字。
接下来 \(q\) 行,每行两个整数 \(x, y\),表示一次查询。
输出格式
输出一行一个整数表示所有询问的答案的按位异或之和。
样例 #1
样例输入 #1
2 2
2 1 2
3 4 5 6
2 2
1 2
样例输出 #1
7
提示
样例 1 解释
第一次询问的结果为 \(5\),第二次询问的结果为 \(2\)。他们做按位异或的结果为 \(7\)。
数据规模与约定
对于全部的测试点,保证 \(1 \leq n, q, s_i \leq 3 \times 10^6\),\(0 \leq a_i \lt 2^{32}\),\(1 \leq x \leq n\),\(1 \leq y \leq s_x\),且 \(\sum\limits_{i = 1}^n s_i \leq 5 \times 10^6\),即 \(s_1 + s_2 + \dots + s_n \leq 5 \times 10^6\)。
解析
通过对数据的分析,我们很快会发现数据范围中的 \(5e6\)的大小很容易MLE
这时考虑使用动态数组vector
代码
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
const int MAXN=5e6;
vector<int > a[MAXN];
int n,q;
int x,y;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++)
{
int op;
cin>>op;
{
for(int j=1;j<=op;j++)
{
int f;
cin>>f;
a[i].push_back(f);
}
}
}
int ans=0;
for(int i=1;i<=q;i++)
{
cin>>x>>y;
ans^=a[x][y-1];
}
cout<<ans<<endl;
return 0;
}
总结
vector在实际使用的意义中,常用于作为动态数组。
挖坑
下一篇大概会讲queue和deque罢