中缀表达式求值,栈

思路

我们定义两个栈,一个栈中存放数字,一个栈中存放运算符 + - * / ( )

我们认为,乘除的优先级 > 加减的优先级 > 括号的优先级

我们定义一个操作,操作内容如下:从数字栈中取出两个数字,从运算符栈中取出一个运算符,按照该运算符对这两个数字做计算,把计算结果重新压入栈。比如先取出数字b,然后取出数字a,运算符是-,那么就把a-b压入数字栈。

我代码的流程是这样的:

首先,从前往后扫描表达式字符串,如果遇到数字那么直接压入栈中。如果遇到的是运算符,那么分以下情况讨论:

  • 如果是左括号(,那么直接压入运算符栈。
  • 如果是右括号),那么执行上面定义的操作,直至运算符栈栈顶为左括号(,然后弹出该栈顶。
  • 如果当前运算符不是括号,再细分为两种情况:
      1. 如果运算符栈为空或者当前运算符优先级大于栈顶运算符,那么直接把该运算符压入栈。
      1. 如果不满足1中的条件,那么重复执行上面定义的操作,直至满足1中的条件,然后把该运算符压入栈。

最后,重复执行上面定义的操作,直至数字栈只剩一个元素,这个元素就是表达式的运算结果。

代码

(输入需满足:所有的数都是正整数;不超出int范围;是合法表达式;除法运算规则为向0整除,即与c++、java整除规则一致。)

样例输入11-((1-3))*2-30/(1+2)
样例输出1-5

样例输入2(3/((1)*1)-3)+2*3-1-2-1-((1-3))*2-3+1-3-3-3*2-((2*2)+1*3)*3+2-2*3+3+1+2+(3+3)/3/2*3+2-(1*2/1)+2*3+2/2+3+(((2*2)))*2+2*2/2*2-(1/3)-1+3/2-1+((3*2)/3*2)+3*3*2*2+1-2+(1+1)*1+2*2+2*3-2+(((2*2)))-2*2+2-2-3-2-(3-2+2)/3*2/2/2/3-2+(1*1)*3*3*1+((2*(1-3)))*1*3/1+3*1*2-(((2+2))/3)*2*3*1+3/(3/3*1)*1*2*2*1-3*(1-2)*3/2/1+(3*((1)*2))*3/1-1*2*2/2+((3*(2)*3)*1)+1*2*1-2+(1*(1*3))/1+1/2/3-((1/3))/2*2+2/1+3/(2*2*3)*3/3*3+2-((1/(1+1)))/3-1/3*1+3-2-((2*2))+2-3+2/1+((1/1-1)+2)/3*3-1-2+1-(3*2)/3+3-3-(2+1)*2+2*2-1-(3-((1)*2)*1)-1/3-2+3-(1*(3)+3)*3+1*3*3*2+((3*1))*1/2-1-3+((1+3*2)+1)/1/1/1+3*2-1/(1/3-1+2)+1*2+2-2*3+2*3/((2-1))+3-1/1-2/2-(3-3+3)*2*3+2-((3/(3))*1)/3*1*1+(((2-3)*2))/3-2+3+1-(3*2/3)*3*1*1*3-(3/(2*3)/2)+3/3*3-2*2-2+((2*3-3))/3-3-1+2*1*1-(3*3)/1*(2-2)*3*2-1-3*3+(2*(3*3))+3/2+1*3-(((3*3))*3)*1/1+3-(3*(3*3)/3-1)*3+3-2-1+2+(((1*2))*1)+2*3*2+2*((1+1*3)*1)-3+2*3-1*2+(3*2-(2)*2)/2*3*1-3+1+2-((1*(3)*3+3))+3+1/1/2+2*1+1+1*((3+2))/3*2-2-1*1-(3/(3+3)*3)/2-3*3-1-2-1+(1/3)+2-3*1*1-(3/(3+3))*2-3*3-3-((3*1)/2)+3+3*1/3/3-(2-1-1)/2-1*1*2+(3+1)*1+2*2*3-1+((1-3)+1)-3*1/3+((1-3))+3-1/3*2+(1-(3*2)+1)*1/1*2/1+(((2*3)))/2*2*3*2-((3/2))-(1+2*1)+2+2/3-3*1-(3*(2/1+2))-3+1-3/3+1*2-(((1/1))*2)+3*1*2+(3/(2*(2))+3)*1*1*3-2*3+(2/(1-(1-3))*1)*1*3+2/2*1-(3-1*1+2)/1/1/2*1+((3-3-1)-2)+1-3*3/1-3/3*2*(3+3)-3*2*2+1+3-3*(1/2)*1*3/1+(2/3+(2)+1)-2+2+3/3-((1-2)+1)/2-1*3+1*((2*2-2)/1)+3*3*3*3*3-((3*(3))-3)+1*1*3*2+1+(3-2/1)*2*2+3*1+1+1*((1-2))-2/2-1+3+2+(3-(2+2))-2-2/2-2*3/1+2/(1*1/3+1)-3+2-2*3-2+((1+2)*3)/2-1-3-1*1-2+2*(((2/1)))/2-3*1-1*3+(1/3-(1*3))*2*3/2*3/2-((1*3))/2-2*1/2+2/2*(3-3)+1-3*1+2+(1+(1-3))-1+2-2+1-(2-1)+1/2-2*2+2-((1-3*2)+2)/3*1*3-3-1-((3-(2*3)))*3-1*3*1*1-1+((3*(1))*3)+3*1-2+((3*2))+3+1*3*3+3+(3*1)*1*(3/1)*2*1-2*1/2+(3-(2)*3)+2-3-3-2+2-((1/1))*2*1/1*2/3+(2*3)-2+3/3+1*1-((1+(3))*2)*2+1+2*3+(3-(1+2))-2-3*2*2*2-3+(3+(1)/3)/2*3+3*3-3-(((2*2))*1)*2/1/1*1*1*1-(3/1)*1/2/1-3/3+1-1+(2-(3-1))*2+2*2*2*1-3+((3+(1))*2)*2+1-2/3*1+(2+(1)*1-3)/2*1/1+3+(2-1*3)/2+3*3+2*2+(3*2*1-3)+2+3*2-1-1*(3*2)*2-2/1-2-3*1
样例输出2275

代码肯定是对的,因为在OJ上能跑通。

#include <iostream>
#include <stack>
#include <map>
using namespace std;
stack<int> num; // number 数字
stack<char> op; // operate 操作符
map<char, int> pri; // priority 预算符优先级
// 字符串转为数字
int toInt(string s){
    
    
	int ans = 0;
	for(int i = 0; i < (int)s.size(); i++){
    
    
		ans = ans * 10 + s[i] - '0';
	}
	return ans;
}
// calculate 计算
int calc(int a, int b, char x){
    
    
	switch (x) {
    
    
		case '+': return a + b;
		case '-': return a - b;
		case '*': return a * b;
		case '/': return a / b;
	}
}
// do operation 从栈顶取出两个数和一个运算符做运算,结果压入栈
void doOp(){
    
    
	// 注意先取的数,运算时放后面
	int b = num.top(); num.pop();
	int a = num.top(); num.pop();
	char x = op.top(); op.pop();
	num.push(calc(a, b, x));
}
int main(){
    
    

	pri['+'] = pri['-'] = 1;
	pri['*'] = pri['/'] = 2;
	pri['('] = pri[')'] = 0;
	
	string s; cin >> s;
	
	for(int i = 0; i < (int)s.size(); i++){
    
    
		// 如果是数字,则取出该数字并压入栈
		if(pri.count(s[i]) == 0){
    
    
			int st = i;
			// 考虑到可能是多位数
			while(pri.count(s[i]) == 0 && i < (int)s.size()){
    
    
				i++;
			}
			int x = toInt(s.substr(st, i - st));
			num.push(x);
			i--;
		}
		else{
    
    
			// 如果是左括号,直接入栈
			if(s[i] == '('){
    
    
				op.push(s[i]);
			}
			// 如果是右括号,对左右括号之间的所有运算符做运算
			else if(s[i] == ')'){
    
    
				while(op.top() != '('){
    
    
					doOp();
				}
				op.pop();
			}
			// 如果当前运算符的优先级大于栈顶运算符,或者运算符的栈为空,把当前运算符压入栈
			else if(op.size() == 0 || pri[s[i]] > pri[op.top()]){
    
    
				op.push(s[i]);
			}
			// 如果当前运算符优先级小于等于栈顶预算符
			// 则一直doOp,直至当前运算符优先级大于栈顶预算符,然后把当前运算符压入栈
			else{
    
    
				while(op.size() != 0 && pri[s[i]] <= pri[op.top()]){
    
    
					doOp();
				}
				op.push(s[i]);
			}	
		}
	}
	// 一直doOp,直至栈中只剩一个数
	while(num.size() > 1){
    
    
		doOp();
	}
	cout << num.top() << endl;
}

猜你喜欢

转载自blog.csdn.net/m0_52744273/article/details/130188082