一.Stack
stack是一种先进后出的数据结构
1.定义:
stack<data_type>stack_name;
例:stack<int> s;
2.stack容器内元素的访问:
只能用top()来访问栈顶元素
3.stack常用操作:
s.empty()--返回bool型,判断栈内是否为空
s.size()--返回栈内元素个数
s.top()--返回栈顶元素值
s.pop()--移除栈顶元素
s.push(a)--向栈内压入一个元素a
4.stack常见用途
stack用于模拟实现一些递归,防止程序对栈内存的限制而导致程序运行错误
5.stack例题:
(1).进制的转换
例:
十进制转化为二进制
描述
进制之间的转换是很常见的操作
输入
一个正整数
输出
对应的二进制
样例输入
9
样例输出
1001
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
stack<int> a;
int i,n,s=0;
cin>>n;
for(i=1;n>0;i++)
{
if(n%2==1)
a.push(1);
else
a.push(0);
n=n/2;
s++;
}
for(i=s;i>0;i--)
{
cout<<a.top();
a.pop();
}
return 0;
}
(2).火车站中的驶出的火车
描述
有编号从1到N的N辆火车等待进入车站,而车站的容量是有限的,需要对火车进行调度。
只有两种调度指令,进站和出站。
现在车站给出了M个指令,请你输出在完成这些调度指令后,车站中驶出火车编号。
输入
两行
第一行两个整数,N和M
第二行为M个为-1或者为1的整数,-1代表出站,1代表入站
输出
一行整数,为驶出车站的火车编号
样例输入
3 3
1 -1 1
样例输出
1
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
stack<int> a;
int n,m,i,b,s=1;
cin>>n>>m;
for(i=1;i<=m;i++)
{
cin>>b;
if(b==1)
{
a.push(s);
if(s!=n)
s++;
}
else
if(b==-1)
{
cout<<a.top()<<" ";
a.pop();
if(s!=1)
s--;
}
}
return 0;
}
二.queue
queue是一种先进先出的数据结构,底端加入元素,顶端取出元素
1.定义
queue<data_type>queue_name;
例:queue<int> q;
2.queue容器内元素的访问:
front()访问队首元素
back()访问队尾元素
3.queue常用操作:
q.empty()--表示queue是否为空
q.size()--返回queue内元素个数
q.front()--查询队首元素
q.back()--查询队尾元素
q.pop()--移除queue中的队首元素
q.push(a)--将一个元素a置入queue的末尾
4.queue常见用途:
需要实现广度优先搜索时,可以用queue代替自己手动实现的一个队列,以提高程序的准确性
5.queue例题:
(1).约瑟夫问题(洛谷p1996):
一群小朋友做成一个圈,已经按照1,2,……,n编号。从1号小朋友开始报数,报到k的小朋友出局;下一个小朋友继续从1开始报。显然,游戏进行到最后,场上只会剩下一个小朋友。此时这个小朋友获胜。现在的问题是,给定n和k,问被淘汰的n-1个小朋友出局的顺序。
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,k,i=1;
queue<int> q;
cin>>n>>k;
for(i=1;i<=n;i++)
q.push(i);
while(q.size()!=1)
{
for(i=1;i<k;i++)
{
q.push(q.front());//形成一个环
q.pop();
}
cout<<q.front()<<" ";
q.pop();
}
return 0;
}
(2).周末舞会.
描述
假设在周末舞会上,男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头上各出一人配成舞伴。规定每个舞曲能有一对跳舞者。若两队初始人数不相同,则较长的那一队中未配对者等待下一轮舞曲。现要求写一个程序,模拟上述舞伴配对问题。
输入
两行
第一行两个整数n和m,分别为两队的长度
第二行一个整数k,表示舞曲的数目
输出
k行,每行两个整数n1和m1,表示配对的编号
样例输入
4 3
6
样例输出
1 1
2 2
3 3
4 1
1 2
2 3
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
queue<int> q1,q2;
int n,m,k,i;
cin>>n>>m>>k;
for(i=1;i<=n;i++)
q1.push(i);
for(i=1;i<=m;i++)
q2.push(i);
for(i=1;i<=k;i++)
{
q1.push(q1.front());
cout<<q1.front()<<" ";
q1.pop();
q2.push(q2.front());
cout<<q2.front();
q2.pop();
cout<<endl;
}
return 0;
}
三.vector
1.定义
vector<data_type>vector_name;
例:vector<int> v;
2.vector容器内元素的访问:
(1).通过下标访问:
如v[0],v[1]
(2).通过迭代器访问
如:vector<int>::iterator it=vi.begin();
3.常用操作:
v.empty()--表示vector是否为空
v.size()--返回vector内元素个数
v.push_back(a)--将元素a插入最尾端
v.pop_back()--将最尾端元素删除
v.clear()--清空vector中所有元素
v.insert(v.begin()+2,-1)--将-1插入v[2]的位置
v.erase(vi.begin()+3)--删除v[3]
v.erase(vi.begin()+1,vi.begin()+4)--删除v[1]--v[3]
v[i]类似数组取第i个位置的元素
4.vector常见用途:
(1).储存数据
(2).用邻接表存储图
5.vector例题:
(1).询问学号(洛谷p3156)
题目描述
有n(n≤2×10 ^ 6) 名同学陆陆续续进入教室。我们知道每名同学的学号(在 1 到 10^ 9之间),按进教室的顺序给出。上课了,老师想知道第 i 个进入教室的同学的学号是什么(最先进入教室的同学i=1),询问次数不超过 10^5次。
输入格式
第一行 2 个整数 n 和 m,表示学生个数和询问次数。
第二行 n 个整数,表示按顺序进入教室的学号。
第三行 m 个整数,表示询问第几个进入教室的同学。
输出格式
m 个整数表示答案,用换行隔开。
输入输出样例
输入
10 3
1 9 2 60 8 17 11 4 5 14
1 5 9
输出
1
8
5
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
vector<int> v;
int n,m,id,i,k;
cin>>n>>m;
for(i=0;i<n;i++)
{
cin>>id;
v.push_back(id);
}
for(i=0;i<m;i++)
{
cin>>k;
cout<<v[k-1]<<endl;//因为vector首元素为v[0],所以此处第k个人编号应该输出v[k-1]
}
return 0;
}
(2).寄包柜(洛谷p3613)
题意:超市里有n个寄包柜。每个寄包柜格子数量不一,第i个寄包柜有 ai个格子。对于每个寄包柜,格子编号从1开始,一直到 ai。现在有q次操作:
1 i j k:在第i个柜子的第j个格子存入物品 k,当k=0时说明清空该格子。
2 i j:查询第i个柜子的第j个格子中的物品是什么,保证查询的柜子有存过东西。
输入格式
第一行 2 个整数 n 和 q,寄包柜个数和询问次数。
接下来 q 个整数,表示一次操作。
输出格式
对于查询操作时,输出答案。
输入输出样例
输入 #1
5 4
1 3 10000 114514
1 1 1 1
2 3 10000
2 1 1
输出 #1
114514
1
代码:
#include<bits/stdc++.h>
using namespace std;
int n,q,a,i,j,k;
int main()
{
cin>>n>>q;
vector<vector<int>> v(n+1);//初始化,从0-n号寄包柜
while(q--)
{
cin>>a;
if(a==1)
{
cin>>i>>j>>k;
if(k==0)
v.clear();
if(v[i].size()<j+1)//如果寄包格不够大
v[i].resize(j+1);//扩大新的寄包格,直到能装下
v[i][j]=k;
}
else
{
cin>>i>>j;
cout<<v[i][j]<<endl;
}
}
return 0;
}
四.priority_queue
队首元素一定是当前优先队列中优先级最高的那一个
1.定义
例如:
priority_queue<int> q;
2.priority_queue容器内元素的访问
top()访问队首元素
3.常用操作:
q.push(a)--将元素a置于优先队列
q.top()--返回优先队列的下一个元素
q.pop()--令队首元素出队
q.empty()--检测优先队列是否为空
q.size()--返回优先队列中元素个数
4.priority_queue内元素优先级设置
(1).基本数据类型的优先级设置
一般是数字大的优先(如果是char型,则是字典序最大的)
特别定义方法:
priority_queue<int, vector<int>, less<int>> q;
vector<int>填写的是来承载底层数据结构堆(heap)的容器,如果第一个参数是double或char,此处需填写vector<double>,vector<char>,less<int>则是对第一个参数的比较类,less<int>表示数字大的优先级越大,greater<int>表示数字小的优先级越大
(2).结构体的优先级设置
如果希望结构体按结构体中某一数据成员的大小划分优先级,就需要重载‘<’(重载是指对已有的运算符进行重新定义)
例:
struct fruit
{
string name;
int price;
friend bool operator<(fruit f1,fruit f2)//友元函数重载运算符
{
return f1.price<f2.price;
};
5.常见用途
(1).解决一些贪心问题
(2).可以对Dijkstra算法进行优化
注意:
使用top()函数前,必须使用empty()判断优先队列是否为空,否则可能会因为队空而出现错误
4.pripority_queue例题
小明很想吃果子,正好果园果子熟了。在果园里,小明已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。小明决定把所有的果子合成一堆。 因为小明比较懒,为了省力气,小明开始想点子了:
每一次合并,小明可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。小明在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以小明在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使小明耗费的体力最少,并输出这个最小的体力耗费值。
例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以小明总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。
输入
第一行输入整数N(0<N<=10)表示测试数据组数。接下来每组测试数据输入包括两行,第一行是一个整数n(1<=n<=12000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。
输出
每组测试数据输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。
样例输入
1
3
1 2 9
样例输出
15
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,N,ai,s,sum;
priority_queue<int,vector<int>,greater<int>> q;
cin>>N;
while(N--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>ai;
q.push(ai);
}
sum=0;//保证上一次的体力耗费值不干扰本次
while(q.size()!=1)
{
s=0;
s+=q.top();
q.pop();
s+=q.top();
q.pop();
sum+=s;//求体力耗费值最小值总值
q.push(s);//将新堆压入优先队列中
}
q.pop();//删除优先队列中最后一个元素
cout<<sum<<endl;
}
return 0;
}
五.set
1.定义:
set<typename> name;
例:
set<int> s;
2.set容器内元素的访问
只能通过迭代器iterator访问
与vector迭代器访问类似
注意:除开vector、string之外的stl容器都不支持*(it+i)访问方式
3.常用操作:
s.insert()--将x插入set容器内,并自动递增排序和去重
s.find()--返回set中对应值为value的迭代器
s.erase()--删除元素
s.size()--获取set中元素个数
s.clear()--清空set中元素
4.常见用途:
自动去重按升序排序
5.set例题:
题目描述
读入n个数,要求输出出现的不同数字的个数
输入:
第一行读入一个 n ( 0<n<=1000000)
第二行读入n个整数k (-2^31 <= k < 2^31 )
输出:
输出一个整数答案
样例输入
5
1 3 1 99999999 3
样例输出
3
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,k;
set<int> st;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>k;
st.insert(k);
}
cout<<st.size()<<endl;
return 0;
}