1.vector
#include <cstdio>
#include <vector>
using namespace std;
vector<int> arr;
int n;
int main()
{
scanf("%d",&n);
//为arr分配初始容量为n+1个元素
//arr的下标为0-n
//默认所有元素的值都是0
arr.resize(n+1);
int i;
//为从下标为1至下标为n的元素赋值
for(i=1;i<=n;i++)
{
scanf("%d",&arr[i]);
}
//输出从下标0到下标n的元素
for(i=0;i<=n;i++)
{
if(i>0)
printf(" ");
printf("%d",arr[i]);
}
//输出的第一个元素值应该是0 因为第一个元素并未被赋值
printf("\n");
return 0;
}
另外,如果不知道容器中一共需要存储多少个元素,可以暂不指定大小,先往容器中插入,这样整个数组就是动态的。
#include <cstdio>
#include <vector>
using namespace std;
vector<int> arr;
int n;
int main()
{
scanf("%d",&n);
int temp;
int i;
//向容器中插入n个元素
for(i=1;i<=n;i++)
{
scanf("%d",&temp);
arr.push_back(temp);
}
//输出从下标0到下标n-1的元素
for(i=0;i<n;i++)
{
if(i>0)
printf(" ");
printf("%d",arr[i]);
}
printf("\n");
//获取动态数组的长度
int len=arr.size();
printf("The length of arr is %d.\n",len);
return 0;
}
利用push_back(temp)向容器中添加值为temp的元素,利用size()获取动态数组当前存储元素的个数。
此外,pop_back()会删除动态数组中最后一个元素,如下所示(先往数组中添加n个元素,然后从后往前删除3个元素):
#include <cstdio>
#include <vector>
using namespace std;
vector<int> arr;
int n;
int main()
{
scanf("%d",&n);
int temp;
int i;
//向容器中插入n个元素
for(i=1;i<=n;i++)
{
scanf("%d",&temp);
arr.push_back(temp);
}
//输出从下标0到下标n-1的元素
for(i=0;i<n;i++)
{
if(i>0)
printf(" ");
printf("%d",arr[i]);
}
printf("\n");
for(i=0;i<3;i++)
{
arr.pop_back();
}
//获取动态数组的长度
int len=arr.size();
//输出动态数组中现存的所有元素
for(i=0;i<len;i++)
{
if(i>0)
printf(" ");
printf("%d",arr[i]);
}
printf("\n");
printf("The length of arr is %d.\n",len);
return 0;
}
此外,容器可以在声明的同时指定元素个数,一般写在函数体中,如下所示:
#include <cstdio>
#include <vector>
using namespace std;
int n;
int main()
{
scanf("%d",&n);
//为arr分配初始容量为n+1个元素
vector<int> arr(n+1);
//arr的下标为0-n
//默认所有元素的值都是0
arr.resize(n+1);
int i;
//为从下标为1至下标为n的元素赋值
for(i=1;i<=n;i++)
{
scanf("%d",&arr[i]);
}
//输出从下标0到下标n的元素
for(i=0;i<=n;i++)
{
if(i>0)
printf(" ");
printf("%d",arr[i]);
}
//输出的第一个元素值应该是0 因为第一个元素并未被赋值
printf("\n");
return 0;
}
2.map
map<数据类型1,数据类型2>表示以数据类型1为下标类型的数组。什么意思呢,就是说数据类型1相当于数组的index,在数组int a[5]中,a[0]即第一个元素,0就是其index。那么在map<string,int> mp中,mp["张三"]=1,"张三"就是mp["张三"]的下标。
以下面一个例题为例:
输入一组姓名和一组查询,你需要做的是对每一个查询输出该姓名出现的次数。
输入格式:输入姓名的个数n,查询的个数m,随后n行输入n个姓名,随后m行输入m个需要查询出现次数的姓名。
输出格式:name共出现过num次,name为查询时输入的姓名,num为name出现的次数。
代码如下:
#include <cstdio>
#include <map>
#include <iostream>
using namespace std;
int n,m;
map<string,int> dp;
int main()
{
//n为输入的姓名的个数
//m为查询的个数
cin>>n>>m;
int i;
string temp;
for(i=0;i<n;i++)
{
cin>>temp;
dp[temp]++;
}
for(i=0;i<m;i++)
{
cin>>temp;
cout<<temp<<"共出现过"<<dp[temp]<<"次"<<endl;
}
return 0;
}
从上面的代码也可以看出,map<string,int> dp中未曾出现过的index其对应的元素值默认为0,比如index中已经出现过"张三",并令dp["张三"]=1,index中没有出现过李四,那么访问dp["李四"]时其值为0。同理map<int,int>中未曾出现过的index其对用的元素值默认也为0。
另外,map还有查找某个index存在与否的功能,将上面的例题稍加改变,最后查询结果为该姓名是否出现过,若出现过则显示Yes,未出现过则显示No。代码如下:
#include <cstdio>
#include <map>
#include <iostream>
using namespace std;
int n,m;
map<string,int> dp;
int main()
{
//n为输入的姓名的个数
//m为查询的个数
cin>>n>>m;
int i;
string temp;
for(i=0;i<n;i++)
{
cin>>temp;
dp[temp]++;
}
for(i=0;i<m;i++)
{
cin>>temp;
if(dp.find(temp)==dp.end())
{
cout<<"No"<<endl;
}
else
{
cout<<"Yes"<<endl;
}
}
return 0;
}
dp.find(index)==dp.end()则表示未出现过以index为下标的元素。
3.set
set翻译成中文就是集合,学过高中数学的都知道,集合中是不允许相同元素存在的,因此在遇到有去重需求的问题时,采用set即可。set的底层使用了特殊的数据结构,可以快速有效地进行插入、删除和查找。
声明:
//声明
set<int> s;
插入操作:
//插入操作
int a=5;
s.insert(a);
获取set中元素的个数:
int num=s.size();
遍历:
#include <cstdio>
#include <set>
using namespace std;
int n;
set<int> s;
int main()
{
//n为输入的整数的个数
scanf("%d",&n);
int i;
int temp;
for(i=0;i<n;i++)
{
scanf("%d",&temp);
s.insert(temp);
}
//遍历
for(set<int>::iterator it=s.begin();it!=s.end();it++)
{
if(it!=s.begin())
printf(" ");
int now=*it;
printf("%d",now);
}
return 0;
}
查找(类似map):
if(s.find(temp)==s.end())
{
printf("查找不到\n");
}
else
{
printf("能查找到\n");
}
4.pair
pair翻译成中文就是“双”、“对”的意思,因此pair<数据类型1,数据类型2>就表示一对数据类型,pair可以作为元素插入到map中,当然也可以从map中读出pair,访问pair中前面的元素用first,访问pair中后面的元素用second。
//前面有过声明语句pos<string,int> ans;
for(map<string,int>::iterator it=ans.begin();it!=ans.end();it++)
{
pair<string,int> now=*it;
cout<<now.first<<" "<<now.second<<endl;
}
5.priority_queue
priority_queue翻译成中文是“优先队列”的意思,是STL中提供的模板,其底层是用堆实现的,顶部或者说优先出队的元素是所有元素中最大或者最小的,也就是对应着大顶堆和小顶堆,默认是大顶堆。将优先队列作大顶堆用还是作小顶堆用,是在声明时决定的。
声明一个大顶堆的语句如下:
//采用默认的优先队列声明方式即可
priority_queue<int> que;
或者如下声明,是在强调que是一个大顶堆:
priority_queue<int,vector<int>,less<int> > que;
声明一个小顶堆的语句如下:
priority_queue<int,vector<int>,greater<int> > que;
有两点需要注意,一是在声明大顶堆的时候用less<int>,而在声明小顶堆时用greater<int>;二是声明语句应避免出现两个'>'连用,如果连用编译器就会报错,中间需要用一个空格隔开。
获取堆顶元素:
int now=que.top();
将堆顶元素拿出:
que.pop();
获取堆中元素的个数:
int length=que.size();
判断堆是否已经为空:
bool isEmpty=que.empty();
6.<algorithm>
<algorithm>中提供了很多方法,可以用一行代码完成一些原本需要好多行代码才能完成的操作,可以减少代码量使逻辑更加清晰。
①fill
fill方法用于给数组中的元素指定初始值,可以是常规数组,也可以是vector,使用方法如下:
第一个参数是指定元素值的起始位置,第二个参数是指定元素值的中止位置的后一个元素的位置,第三个参数是指定值。
int arr[100];
int n=100;
fill(a,a+n,10);
以上代码是对数组arr中的全部元素赋初始值为10。
vector<int> arr;
arr.resize(100);
int n=100;
fill(arr.begin(),arr.end(),10);
以上代码也是对数组arr中的全部元素赋初始值为10。
②reverse
reverse翻译成中文是“翻转”的意思,功能是把数组中的元素倒过来放置,{1,2,3,4,5}反转完变成{5,4,3,2,1},操作对象可以是数组,也可以是vector,使用方法如下:
int arr[100];
int n=100;
//...经过一系列初始化...
reverse(arr,arr+n);
以上代码是将从地址为arr的元素起往后n个元素倒置。
vector<int> arr;
//...经过一系列初始化...
reverse(arr.begin(),arr.end());
以上代码是将数组arr中全部的元素倒置。
7.<cmath>
<cmath>是一个跟数学运算有关的库文件,里面提供了很多数学函数可以直接拿来用。
①向下取整、向上取整与四舍五入:
#include <cstdio>
#include <cmath>
using namespace std;
int n;
int main()
{
scanf("%d",&n);
double sum=0.0;
int i;
int temp;
for(i=0;i<n;i++)
{
scanf("%d",&temp);
sum+=temp;
}
printf("真实结果为%lf.\n",sum/n);
int ans=floor(sum/n);
printf("向下取整的结果为%d.\n",ans);
ans=ceil(sum/n);
printf("向上取整的结果为%d.\n",ans);
ans=round(sum/n);
printf("四舍五入的结果为%d.\n",ans);
return 0;
}
以上代码描述的是一个求解平均数的程序,floor的中文意思是“地板”,对应向下取整;ceil的中文意思是“天花板”,对应向上取整;round的中文意思是“圆的”,四舍五入显得比较“圆滑”。
②pow函数
pow函数用于求a的b次方,pow(a,b),最原始的pow函数无论是参数还是返回值都是double类型的,因此最好在调用该函数的时候都先将类型转换成double再传入函数。我们都知道呈指数增长是间非常可怕的事情,在运算结果过大时,将其返回到long long int型变量中,其值可能为负数,如下所示:
#include <cstdio>
#include <cmath>
using namespace std;
int n;
int main()
{
long long int a=10000000000;
long long int b=10000000000;
long long int ans=pow(a,b);
printf("%lld\n",ans);
return 0;
}