表达式求值(c++,栈)

题目:

给定一个表达式,其中运算符仅包含 +,-,*,/(加 减 乘 整除),可能包含括号,请你求出表达式的最终值。

注意:

  • 数据保证给定的表达式合法。
  • 题目保证符号 - 只作为减号出现,不会作为负号出现,例如,-1+2,(2+2)*(-(1+1)+2) 之类表达式均不会出现。
  • 题目保证表达式中所有数字均为正整数。
  • 题目保证表达式在中间计算过程以及结果中,均不超过 2^31-1。
  • 题目中的整除是指向 0 取整,也就是说对于大于 00 的结果向下取整,例如 5/3=1,对于小于 0 的结果向上取整,例如 5/(1−4)=−1。
  • C++和Java中的整除默认是向零取整;Python中的整除//默认向下取整,因此Python的eval()函数中的整除也是向下取整,在本题中不能直接使用。
输入格式

共一行,为给定表达式。

输出格式

共一行,为表达式的结果。

数据范围

表达式的长度不超过 105105。

输入样例:
(2+2)*(1+1)
输出样例:
8

 涉及知识点:

一.(stack),是STL中实现先进后出的容器。

头文件:include<stack>

定义:stack<typename>name;

例如:stack<int>st;

st.push(i);    //将i压入栈

a=st.top();    //取栈顶元素

st.pop();       //取出栈顶元素

st.size();       //返回栈内元素个数

二.unordered_map/map

unordered_map是一个关联容器,它将键值存储在哈希表中,可以快速地查找和访问元素。

每个关键字(key)只能在unordered_map/map中出现一次;关键字的值(value)可以重复。该容器能够建立关键字与值之前的映射关系(比如建立字符/字符串与整数之间的映射关系)

与map相比,unordered_map的插入、删除和查找操作都更快,但是它的元素是无序的(所以对于一些有顺序要求的问题,用map;对于查找问题,考虑用unordered_map)

map的使用(unordered_map相似):

1.头文件:#include<map>

2.定义 map<int,string> student;

3.初始化 map<int,string> student={{1,xiaohong},{2,xiaobai}};

4.赋值 student[5]="lisi";

//使用[]进行单个插入,若已经存在key值5,则赋值被修改,若无则插入

//key值作为下标,它可以是任意类型

三.前缀表达式、中缀表达式和后缀表达式

1.前缀表达式(也称为波兰式)是一种没有括号的算术表达式,其运算符写在前面,操作数写在后面。如 -1+2 3 <=>1-(2+3)

2.中缀表达式即人们常用的算术表示方法

3.后缀表达式(也称为逆波兰式)运算符放在两个运算对象后面,所有的计算按运算符出现的顺序,严格从左向右进行,更便于计算机运算(该题目实际上是将中缀表达时转化成后缀表达式进而运算)

思路:

一.建立双栈,一个操作数栈,一个运算符栈

二.从左到右扫描中缀表达式中的每个元素(分四种情况讨论)

1.若当前元素是数字,那么计算出操作数并将其压入操作数栈

2.若当前元素是左括号,则直接将左括号压入运算符栈

3.若当前元素是右括号,则计算栈中的元素直到遇到左括号为止;计算完毕后,右括号不压入栈中,并且将左括号弹出

4.若当前元素是+  -  *  /  运算符,那么将与栈顶运算符的优先级进行比较。若栈顶运算符优先级高于或等于当前运算符优先级,将栈顶运算符弹出并进行运算。重复该步骤,直到栈顶运算符优先级小于当前运算符优先级,再把当前运算符压入栈中。

三.若扫描完中缀表达式后,栈中仍存有元素,则依次运算

在纸上模拟过程如下:(1+2)*3+4

 代码实现如下:

#include<iostream>
#include<stack>
#include<string>
#include<unordered_map>
using namespace std;

stack<int> num;//操作数栈 
stack<char> op; //运算符栈
unordered_map<char,int> h{{'+',1},{'-',1},{'*',2},{'/',2}};//运算符优先级 

//取栈顶运算符x1  栈顶操作数x2
void eval(){
	int a=num.top();num.pop();
	int b=num.top();num.pop();
	char c=op.top();op.pop();
	int r;
	if(c=='+')r=b+a;
	if(c=='-')r=b-a;
	if(c=='*')r=b*a;
	if(c=='/')r=b/a;
	num.push(r);
}

int main(){
	string s;
	cin>>s;
	
	//遍历中缀表达式 
	for(int i=0;i<s.size();i++){
		
		//若s[i]为数
		if(isdigit(s[i])){
			int x=0;               //x为操作数
			while(isdigit(s[i])){
				x=x*10+s[i++]-'0';
			}
			num.push(x);
			i--; 
		}

		//若s[i]为左括号,则直接压入运算符栈(左括号无优先级) 
		else if(s[i]=='(')op.push(s[i]); 
		
		//若s[i]为右括号,则从右往左计算,直到遇到左括号
		else if(s[i]==')'){
			while(op.top()!='(')eval();
			op.pop();//弹出左括号 
		} 
		
		//若s[i]为+-*/运算符 
		//栈顶运算符优先级大于等于新运算符时,先将栈顶运算符取出进行运算,再将新运算符压入栈 
		else{
		 while(op.size()!=0&&h[op.top()]>=h[s[i]])eval();
		 //一定要记得判断运算符栈不为空 
		 op.push(s[i]);
		} 
	}
	while(op.size())eval();(不能用判断语句!)
	cout<<num.top()<<endl;
	return 0;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值