栈stack

本文介绍了栈作为线性存储结构的特性,包括先进后出原则和在栈顶进行的插入、删除操作。通过实例分析了如何使用栈解决后缀表达式计算、括号匹配、模拟栈操作和中缀表达式求值的问题。在中缀表达式求值中,提到了哈希表在处理运算优先级中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

栈的特点

1. 一种线性存储结构,先进后出。

2.限定只能在栈顶进行插入和删除操作。

s.empty();         //如果栈为空则返回true, 否则返回false;
s.size();          //返回栈中元素的个数
s.top();           //返回栈顶元素, 但不删除该元素
s.pop();           //弹出栈顶元素, 但不返回其值
s.push();          //将元素压入栈顶

例1 OJ331 后缀表达式的值

【分析】

1.考虑表达式中数的先后顺序,具体可用树状图来表示。

2.运用栈相关的操作完成加减乘除运算

【代码】

#include <bits/stdc++.h>
using namespace std;
string a;
int main(){
	stack<long long> s;//记得开long long
	getline(cin,a);
	int l=a.size();
	int i=0;//赋初值
	long long m,n;
	while(a[i]!='@'){
		switch(a[i]){
			case '+':n=s.top();s.pop();m=s.top();s.pop();s.push(m+n);break;
			case '-':n=s.top();s.pop();m=s.top();s.pop();s.push(m-n);break;
			case '*':n=s.top();s.pop();m=s.top();s.pop();s.push(m*n);break;
			case '/':n=s.top();s.pop();m=s.top();s.pop();s.push(m/n);break;//运算
			default:
				long long t=0,flag=0;
				while(a[i]>='0' && a[i]<='9'){
					t=t*10+a[i]-'0';
					i++;
					flag=1;
				}
				if(flag) s.push(t);//如果是数字 入栈
				break;
		} 
		i++;//下一位
	}
	cout<<s.top() ;
	return 0;
}

例2 OJ353 表达式括号匹配

【分析】

先考虑将左括号放入栈中(可以直接用别的数代替),再用右括号进行配对。不能先使右括号入栈,那样的运算是非法的。当栈不为空时,每一个右括号,弹出栈中一个元素与其配对。最后当栈为空时,说明全部配对成功;否则,配对失败。(需要考虑栈本身是空的,直接输出“NO”。

【代码】

#include<bits/stdc++.h>
using namespace std;
stack<long long>a;
string s;
int main(){
	cin>>s;
	int i=0;
	while(s[i]!='@'){
		if(s[i]=='('){
			a.push(i);//入栈 
		}
		if(s[i]==')'){
			if(a.empty()==1){
				cout<<"NO";
				return 0;
			}
			else{
				a.pop();//弹出 
			}
		}
	i++;
	}
	if(a.empty()==1) cout<<"YES";
	else cout<<"NO";
}

例3 Acwing 模拟栈

【分析】

1.定义字符串读入四种类型的操作

2.分别操作

【代码1 数组】

#include <bits/stdc++.h>
#define N 1000010
using namespace std;
string a;
int stk[N];
int main(){
    int m,top=0;//top用来指向栈顶元素
    cin>>m;
    while(m--){
    	cin>>a;
    	if(a=="push"){
    	int x;
    	cin>>x;
    	stk[++top]=x;
		}
		if(a=="pop"){
			top--;
		}
		if(a=="query"){
			cout<<stk[top]<<endl;
		}
		if(a=="empty"){
			if(top<=0){
				cout<<"YES"<<endl;//说明栈为空
			}
		else cout<<"NO"<<endl;
		}
	}
	return 0;
}

【代码2 stl】

#include <bits/stdc++.h>
#define N 1000010
using namespace std;
string a;
stack<long long> s;
int main(){
    int m;
    cin>>m;
    while(m--){
    	cin>>a;
    	if(a=="push"){
    	int x;
    	cin>>x;
    	s.push(x);//x入栈
		}
		if(a=="pop"){
			s.pop();
		}
		if(a=="query"){
			cout<<s.top()<<endl;//输出栈顶元素
		}
		if(a=="empty"){
			if(s.empty()){
				cout<<"YES"<<endl;
			}
		else cout<<"NO"<<endl;
		}
	}
	return 0;
}

例4 Acwing 表达式求值

【分析】

1.和后缀表达式一样,运用树来理解,进行中序遍历。

2.注意考虑括号的问题,遇到右括号需要计算到相应的左括号之间的值

3.注意‘ + ’‘ - ’ ‘ * ’ ‘ / ’的运算优先级,运用哈希表(头文件为<unordered_map>)。

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表

给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。应用详见代码。】

【代码】

#include <iostream>
#include <cstring>
#include <stack>
#include <algorithm>
#include <unordered_map>
using namespace std;
stack<int> num;
stack<char> op;//num用来存放数值,op用来存放运算符
void eval(){
	int b=num.top();num.pop();
	int a=num.top();num.pop();//注意b和a的顺序
	char c=op.top();op.pop();
	int x=0;
	if(c=='+') x=a+b;
	if(c=='-') x=a-b;
	if(c=='*') x=a*b;
	if(c=='/') x=a/b;
	num.push(x);
}//计算函数
int main(){
	unordered_map<char,int> pr{{'+',1},{'-',1},{'*',2},{'/',2}};//哈希表 运算等级
	string str;
	cin>>str;
	for(int i=0;i<str.size();i++){
		auto c=str[i];
		if(isdigit(c)){
			int x=0,j=i;//j从i开始遍历
			while(j<str.size()&&isdigit(str[j])){
				x=x*10+str[j++]-'0';
			}
			i=j-1;//时刻更新i的值
			num.push(x);//将数字存入数组
		}
		else if(c=='(') op.push(c);//存入左括号
		else if(c==')'){
			while(op.top()!='(') eval();
			op.pop();
		}//当遇到右括号时,从右到左运算到左括号,并弹出
		else{
			while(op.size()&&pr[op.top()]>=pr[c]) eval();
			op.push(c);//根据优先级 存入运算符
		}
	}
	while(op.size()) eval();//运算剩下的
	cout<<num.top()<<endl;
	return 0;
}

(ps:本题参照yxc)

另一个思路是把中缀表达式转换成后缀表达式求值 另开一个数组用来存放 还有计算函数以及优先级的设定 但需要注意判断合法的情况

类似的 OJ1358 中缀表达式

详见 ​​​​​​​

练习1 OJ357 车厢调度​​​​​​​

【代码】

#include <cstdio>
#include <iostream>
#include <stack>
using namespace std;
stack<char> t;
int a[1005];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	int i=1,m=1;//i为指针,b为入栈的数 
	while(i<=n&&m<=n+1){//不能超过总车厢数 
		if(!t.empty()&&a[i]<=t.top()){//栈内不为空且当前车厢编号小于等于栈顶元素 
			i++;//i指向下一位 
			t.pop();//当前车厢驶出 
		}
		else t.push(m++);//否则 继续入栈 
	}
	if(i>n) cout<<"YES";//能够遍历完整个数组 说明可以得到指定顺序 
	else cout<<"NO";
	return 0;
}

源君义

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值