栈与队列使用详解
咳咳,老规矩,开局扯会犊子,上午刚刚把vector数组预习了一遍,晚上决定来看看栈,栈和队列作为非非非非非非非非非非常重要的数据结构之一,还是很有必要去学会的,咱就不去说那个先入后出的原理了,那玩意看的人头大,咱今就来学习他的用法。感谢c++,感谢函数。
- 咳咳,咱就直接上吧,先看看他们的使用方式,然后直接实战!!!
stack栈 | queue 队列 | 说明 |
---|---|---|
stack < Type > s | queue < Type > q | 定义 |
s.top(); | q.front(); | 栈顶或者队首元素 |
s.pop(); | q.pop(); | 删除栈顶或者队首元素 |
s.size(); | q.size(); | 返回栈或者队列的大小 |
s.empty(); | q.empty(); | 判断栈或者队列是否为空 |
- 好,我们现在看一遍应该就会用了哈,是不是超级简单,以前都是被强行要求手动打栈和队列,还是现在舒服,偷懒使人快乐呀。
hdu 1062 “Text Reverse”
题目连接:点我了解题目(这是一个链接)
大意:翻转字符串,例如输入“olleh !dlrow” , 输出 “hello world!”,包含t组数据。
输入样式:
3
olleh !dlrow
m’I morf .udh
I ekil .mca
输出样式:
hello world!
I’m from hdu.
I like acm.
- 认真学过vector数组的朋友现在肯定在想了,直接建立个vector数组,然后使用翻转函数就没了满。想法一来,就想打出来了。
- 咳咳,还别说,这样写真可以,但是你要看清楚哦,这可不是将整个字符串翻转过来,而是将每一个单词翻转过来,这是不一样的。
#include<bits/stdc++.h>
using namespace std;
vector<char > a;
int main(){
int t;
cin >> t;
getchar();
while(t--){
a.clear(); //开局也要清空哦!
while(1){
char ch = getchar();
if(ch=='\n'||ch==EOF||ch==' '){ //遇到单词结尾和整个结尾都需要翻转
reverse(a.begin(),a.end()); //直接使用翻转函数,不给机会
for(int i=0;i<a.size();i++){
cout << a[i] ;
}
//重点就在这里了,如果是结束标记那就直接break。
//准备下一个例子就好了,但是不是的话就要将那个空格给输出来。
if(ch == '\n'|| ch == 'EOF')break;
else cout << " ";
a.clear(); //注意清空a数组哦
}else{
a.push_back(ch);
}
}
cout << endl;
}
return 0;
}
- 咳咳,打了一会便出来了,但是哈,这里这么也是需要一个翻转函数,如果用栈来写的,那就不用翻转了,因为先进后出的特点,他本就是翻转的。所以用栈来写的话,他会更快哦!!!
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin >> t;
getchar();
while(t--){
stack<char > s;
while(1){
char ch = getchar();
if(ch=='\n'||ch==EOF||ch==' '){
//这里我们可以看到哈,没有任何的操作,直接输出就完事
//后面也不需要去清空什么,因为输出一个删除一个。
while(s.size()){
cout << s.top();
s.pop();
}
if(ch == '\n'|| ch == 'EOF')break;
else cout << " ";
}else{
s.push(ch);
}
}
cout << endl;
}
return 0;
}
- 咳咳,这个题目,相对简单哈。我觉得我们可以挑战更加难一点的题目。
hdu 1237 “简单计算机”
题目链接:点我了解题目(这是一个链接)
题目大意:读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
输入样式:
1 + 2
4 + 2 * 5 - 7 / 11
0
输出样式:
3.00
13.36
- 咳咳,看起来有点复杂哈,其实也不是特别难。
- 首先,困难点在哪里呢,要先算乘法和除法对不。然后其余的都没有问题了。
- 那我们可以先输入一个值,然后直接进栈。
- 接下来,我们每次都输入一个操作符和一个值
- 当操作符为 加号 ‘ + ’ 时呢,我们不用管,直接将后面的值入栈。
- 当操作符为 减号 ‘ - ’ 时,我们将这个值的相反数投进去,也就是 -d ,后面就直接累加就好了,不需要考虑减号加号啥的。
- 当操作符为 乘号 ‘ * ’ 或者 除号 ‘ / ’ 时,先有设置个double值,用这个值记录下栈顶元素乘以或者除以后面那个值的值,然后将栈顶元素删除,再将刚刚算好的double值投入到栈里面去。
- 最后依次出栈累加就能就可以得到想要的结果了。
#include<bits/stdc++.h>
using namespace std;
int main(){
double n;
while(~scanf("%lf",&n)) {
stack<double > s;
s.push(n);
double d;
char c;
while(getchar()!='\n'){
scanf("%c %lf",&c,&d);
if(c=='+'){
s.push(d); //加号直接进栈
}
else if(c == '-'){
s.push(-d); //减号,将其相反数进栈
}
else if(c=='*'){ //乘法先算再进栈,除法同理
double sum = d * s.top();
s.pop();
s.push(sum);
}
else if(c == '/'){
double sum = s.top() * 1.0 / d;
s.pop();
s.push(sum);
}
}
if(s.top() == 0 && s.size()==1)break;
double ans = 0;
while(!s.empty()){
ans = ans + s.top();
s.pop();
}
printf("%.2lf\n",ans);
}
return 0;
}
- 是不是感觉超级简单,这就是栈的运用了,这边建议不看代码手撸出来,自己想,那才是最香的说实话。
- 队列的话明天再来搞好了,孩子要去睡觉了,有点困。。。。。
咳咳,一大早咱就来继续了,生怕昨天忘了 ,又找了一题计算器题目来温习温习栈。想起上次有个牛客挑战赛有个题,拉出来练练。
牛客挑战赛46 A题 “奇怪的计算器”
题目链接:点我了解题目(这是一个链接)
题目描述:
牛牛家里有一个计算器。
牛牛不小心把自己的计算器玩坏了。乘法(×)和除法(÷)按钮全都失灵。
所以,牛牛决定以后用它来计算只含加(+)和减(-)的表达式。
最近,牛牛突然发现,这个计算器的幂(^)按钮变成了异或键!本来 5^2=25 的,现在 5^2=7 了。
因此他想知道,输入一个表达式后计算器会返回多少。
该计算器认为优先级异或(^)>加(+),减(-)。
输入样式:
3+5^2-9
输出样式:
1
- emmm,这题我当时没有写出来,当时也是按照以前那样写,先输入一个数,当然依次输入符号和数值,然后加号就进栈,负号就它的相反数进栈,异或符号,就先进行异或,然后累加。
- 这个我没有考虑到一个问题,就是当出现负号后面是异或的时候,因为我进栈的是值的相反数,后面出现异或的时候,它会直接用负数和后面的值进行异或,这样肯定会出问题的,所以没办法,我只能再搞一个栈,专门用来记录正负符号罗。
- 其实,这题可以不用栈写的,直接用个累计变量,一路遍历过去就可以求出来了,但是因为这篇文章是写栈的满,所以我们就用栈来写吧!!!
#include<bits/stdc++.h>
using namespace std;
stack<int >s;
stack<char > f;
int main(){
int n;
scanf("%d",&n);
s.push(n);
char c;
while((c=getchar())!='\n'){ //好好学,原理就是数字后面必定是一个符号
int d;
scanf("%d",&d);
//cout << c <<" " <<d << endl;
if(c=='+'||c=='-'){ //累计值和符号
s.push(d);
f.push(c);
}
else { //当发现异或符号时,那么直接将栈顶元素进行异或
int sum = s.top() ^ d;
s.pop();
s.push(sum);
}
}
int ans = 0;
while(!f.empty()){
if(f.top()=='+')ans = ans + s.top();
else ans = ans - s.top();
s.pop();
f.pop();
}
ans = ans + s.top(); //最后因为还有第一位是没有符号的,所以直接累加就好了
cout << ans << endl;
return 0;
}
- 咳咳,我还是不够细呀,害。考虑事情还是不够全面的。
- 到这是不是栈就搞的差不多了,你是不是在想,为什么全稿栈呀,我的队列呢,来坐坐队列的题目呀,咳咳,我也想呀,主要是队列的例子做的比较少,不好找题目,害,咳咳,不过咱不能不做不是,所以,我们直接来做个栈和队列的模拟题。
hdu 1702 “ACboy needs your help again!”
题目链接:点我了解题目(这是一个链接)
大意:咳咳,就是模拟栈和队列,FILO表示栈,FIFO表示队列,然后IN就是进栈,OUT就是出栈,输出。
输入样式:
4
4 FIFO
IN 1
IN 2
OUT
OUT
4 FILO
IN 1
IN 2
OUT
OUT
5 FIFO
IN 1
IN 2
OUT
OUT
OUT
5 FILO
IN 1
IN 2
OUT
IN 3
OUT
输出样式:
1
2
2
1
1
2
None
2
3
- 咳咳,这个没啥好说的哈,根据我们学过的函数,直接打就行了,没问题。
#include<bits/stdc++.h>
using namespace std;
int main(){
int t,n;
scanf("%d",&t);
string str;
while(t--){
scanf("%d",&n);
cin>> str;
if(str == "FIFO"){ //直接模拟队列
queue<int > q;
while(n--){
string str1;
int m;
cin >> str1;
if(str1=="IN"){
scanf("%d",&m);
q.push(m);
}else{
if(!q.empty()){
cout << q.front() << endl;
q.pop();
}else{
cout << "None" << endl;
}
}
}
}else{ //不是队列,那这个就是栈,直接打
stack<int > s;
while(n--){
string str1;
int m;
cin>> str1;
if(str1=="IN"){
scanf("%d",&m);
s.push(m);
}else{
if(!s.empty()){
cout << s.top() << endl;
s.pop();
}else{
cout << "None" << endl;
}
}
}
}
}
}
- 到这里,基本上栈和队列的使用便已经用的很好了,但是很多时候,题目考的并不是这些简单函数的使用,而是要动动脑子,想问题的,还有就是看看,比谁细了,谁细就能过。那些大佬是真的细。
- 咳咳,对了,队列还有一个优先队列,这个也蛮好用的,这里也一起做一做吧。
优先队列priority_queue
优先队列满,顾名思义就是优先最高的先出队,它可以说是队列和排序的完美结合,不仅可以存储数据,还能对数据进行设定的规则进行排序。每次push和pop操作,优先队列都会进行重新排序,把优先级最高的元素放在前面。
使用方式和栈是一样的。
在STL里面,优先队列是用二叉堆做的,操作一个数的复杂度是O(nlog2n).
- 是不是超级方便,咱直接干。
hdu 1873 “看病要排队”
题目链接:点我了解题目(这是一个链接)
看病要排队这个是地球人都知道的常识。
不过经过细心的0068的观察,他发现了医院里排队还是有讲究的。0068所去的医院有三个医生(汗,这么少)同时看病。而看病的人病情有轻重,所以不能根据简单的先来先服务的原则。所以医院对每种病情规定了10种不同的优先级。级别为10的优先权最高,级别为1的优先权最低。医生在看病时,则会在他的队伍里面选择一个优先权最高的人进行诊治。如果遇到两个优先权一样的病人的话,则选择最早来排队的病人。
现在就请你帮助医院模拟这个看病过程。
输入样式:
7
IN 1 1
IN 1 2
OUT 1
OUT 2
IN 2 1
OUT 2
OUT 1
2
IN 1 1
OUT 1
输出样式:
2
EMPTY
3
1
1
#include<bits/stdc++.h>
using namespace std;
struct node{
int id; //排队id
int pri; //优先级
// friend bool operator <(node a,node b){
// if(a.pri == b.pri)return a.id > b.id;
// return a.pri < b.pri;
// }
// 咳咳,眼熟不,这就是刚刚开始sort排序讲的东西哈,是不是忘记了呀!!!
bool operator < (const node &b)const{
if(pri!=b.pri)return pri < b.pri;
return id > b.id;
}
};
int main(){
int n;
cin >> n;
while(~scanf("%d",&n)){
priority_queue<node > q[5];
string s;
int cnt = 1;
while(n--){
cin >> s;
if(s == "IN"){
int A,B;
cin >> A >> B;
q[A].push(node{cnt++,B});
}else{
int A;
cin >> A;
if(q[A].empty()){
cout << "EMPTY" << endl;
}else{
node now = q[A].top();
cout << now.id << endl;
q[A].pop();
}
}
}
}
return 0;
}
- 咳咳,这就是优先队列哦,快速存储数据,还能按照你指定的规则进行排序,你学废了吗?
- 总感觉哪里不对劲,咳咳,留给你们自己想了,溜了溜了。