栈(stack)与队列(queue)使用详解

16 篇文章 7 订阅

栈与队列使用详解

咳咳,老规矩,开局扯会犊子,上午刚刚把vector数组预习了一遍,晚上决定来看看栈,栈和队列作为非非非非非非非非非非常重要的数据结构之一,还是很有必要去学会的,咱就不去说那个先入后出的原理了,那玩意看的人头大,咱今就来学习他的用法。感谢c++,感谢函数。

  • 咳咳,咱就直接上吧,先看看他们的使用方式,然后直接实战!!!
stack栈queue 队列说明
stack < Type > squeue < 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;
}
  • 是不是感觉超级简单,这就是栈的运用了,这边建议不看代码手撸出来,自己想,那才是最香的说实话。
  • 队列的话明天再来搞好了,孩子要去睡觉了,有点困。。。。。
------------------------------2020/12/15晚------------------------------


咳咳,一大早咱就来继续了,生怕昨天忘了 ,又找了一题计算器题目来温习温习栈。想起上次有个牛客挑战赛有个题,拉出来练练。


牛客挑战赛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;
} 
  • 咳咳,这就是优先队列哦,快速存储数据,还能按照你指定的规则进行排序,你学废了吗?
  • 总感觉哪里不对劲,咳咳,留给你们自己想了,溜了溜了。



--------------------------2020/12/17---------------------------
改革尚未成功,同志仍需努力!!!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木不会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值