表达式求值(1) | C++ | 栈

一、题目描述

背景:

我们的教材中已经介绍了表达式求值的算法,现在我们将该算法的功能进行扩展,要求可以处理的运算符包括:+、-、*、/、%(整数取余)、^(乘方)、(、)。

要求:

采用算符优先算法,计算的中间结果只保留整数。

输入:

第一行为整数N。表示下面有N个表达式

从第二行起的后面N行为N个由整数构成的表达式

输出:

共N行,每行为相应表达式的计算结果。

如果判断出表达式有错误,则输出:error.

如果在计算过程中出现除数为0的情况,则输出:Divide 0.

特殊情况说明:

在表达式中,如果操作数出现负数(例如-8),则要特别注意。例如:
10加-8表示为:10+-8。
10减-8表示为:10--8。

测试输入期待的输出时间限制内存限制额外进程
测试用例 1以文本方式显示
  1. 4↵
  2. 2^3↵
  3. 2^0↵
  4. 2^3^2↵
  5. 2^(3-1)^(10-8)↵
以文本方式显示
  1. 8↵
  2. 1↵
  3. 512↵
  4. 16↵
1秒64M0
测试用例 2以文本方式显示
  1. 11↵
  2. (2+8↵
  3. 2+8)↵
  4. 8/0↵
  5. 8/(8+5-13)↵
  6. 2^(2-5)↵
  7. 10-(80-30(/3*3+4↵
  8. 10-80-30)/3*3+4↵
  9. (2+8)(3+2)↵
  10. (2)3(8)↵
  11. 30(/3+3)+4↵
  12. 10(20-8)+2↵
以文本方式显示
  1. error.↵
  2. error.↵
  3. Divide 0.↵
  4. Divide 0.↵
  5. error.↵
  6. error.↵
  7. error.↵
  8. error.↵
  9. error.↵
  10. error.↵
  11. error.↵
1秒64M0
测试用例 3以文本方式显示
  1. 2↵
  2. 10(10)↵
  3. 14*10-(10)2↵
以文本方式显示
  1. error.↵
  2. error.↵
1秒64M0
测试用例 5以文本方式显示
  1. 14↵
  2. 18-32↵
  3. 18/4↵
  4. 18%3↵
  5. 10+20*4↵
  6. 10-20/4↵
  7. (18-3)*3↵
  8. 10*(10)↵
  9. (10+2)/(8-10)↵
  10. (2*3)/(5*2)↵
  11. 10-(80-30)/3*3+4↵
  12. (((2+8)*2-(2+4)/2)*2-8)*2↵
  13. (((8+2)*(4/2)))↵
  14. 10/0↵
  15. (10-80*2↵
以文本方式显示
  1. -14↵
  2. 4↵
  3. 0↵
  4. 90↵
  5. 5↵
  6. 45↵
  7. 100↵
  8. -6↵
  9. 0↵
  10. -34↵
  11. 52↵
  12. 20↵
  13. Divide 0.↵
  14. error.↵
1秒64M0

二、操作的注意点

使用栈来处理表达式,具体的操作过程就不多说了,基础中的基础。

说几个我在写的过程中遇到的问题吧,提醒下同学们(或者学弟学妹们)。

1、操作负数方面,我采用了字符串,这样当我读到 ‘-’ 的时候,可以直接读它的上一位,不用担心在新的循环里被刷掉。 

如果读到了一个负号,而且它是字符串的第一位或者它的上一位是一个运算符,那么直接跳过。

在读数字的时候,留个心眼,如果它的上一位是负号,而且它的上上一位是运算符,则flag=-1。

2、error的情况。

如果读入了两个连续的运算符,例如**,*^,-%等,它可能是error。

如果指数运算时,指数是负数,也是error。

如果栈内没有与')'匹配的‘(’,是error。

操作结束后,存储操作符的栈不为空,而且也不能计算,是error。

3、divide 0。

当遇到/0和%0时输出divide 0即可。相比于error,divide 0情况就好写很多,别忘了就是。


完整代码

#include<bits/stdc++.h> 
using namespace std;
//clt意为calculate,用来计算两个数的结果 
void clt(int *base, int ind, char op) {
	switch (op) {
		case '+': (*base) = (*base) + ind; break;
		case '-': (*base) = (*base) - ind; break;
		case '*': (*base) = (*base) * ind; break;
		case '/': (*base) = (*base) / ind; break;
		case '%': (*base) = (*base) % ind; break;
		case '^': (*base) = pow((*base),ind); break;
	}
}

//TypeDe判断是数字还是运算符,数字返回1,运算符返回0 
int TypeDe(char c) {
	if (c>='0' && c<='9') return 1;
	else 		   		  return 0;
}

//lvl意为level,定义单个运算符的优先级 
int lvl(char c) {
	switch (c) {
		case '(': return 0;
		case '+': case '-': return 1;
		case '*': case '/': case '%': return 2;
		case '^': return 3;
		case ')': return 4;
	}
}

//cmp意为compare,用来比较运算符之间的优先级 
int cmp(char op_top, char c) {
	int lvl(char);
	if (op_top=='^' && c=='^') return 0;
	if ( lvl(op_top)>=lvl(c) ) return 1;
	else 					   return 0;
}

int main(){
	
	int TypeDe(char); 
	void clt(int*, int, char);
	int cmp(char, char);
	
	int n;
	cin >> n;
	for (int i=0;i<n;i++) {
	
		stack<char> op;
		stack<int> data;
		string Formula;
		cin >> Formula;
		int p=0, len=Formula.length();
		while ( p<len ) {
			if (Formula[p]>='0' && Formula[p]<='9') {
				int flag=1, cnt=0;
				if ( (p==1 && Formula[0]=='-') || (p>1 && Formula[p-1]=='-' && TypeDe(Formula[p-2])==0 ) ) {
					flag = -1;
				}
				while (Formula[p]>='0' && Formula[p]<='9') {
					cnt = cnt*10 + Formula[p] - '0';
					p++;
				}
				data.push(cnt*flag);
			}
		
			else {
				if ( (p==0 && Formula[p]=='-') || (p>0 && Formula[p]=='-' && TypeDe(Formula[p-1])==0 ) ) 
					{  }
				else if ( (Formula[p]!='(') && (Formula[p-1]!=')') && (TypeDe(Formula[p])==0 && TypeDe(Formula[p-1])==0) ) {
					cout << "error." << endl;
					goto m;
				}
				else {
					if ( op.size() && ( (op.top()!='(' && Formula[p]==')') || (cmp(op.top(), Formula[p]))>0 ) && Formula[p]!='(') {
						while ( op.size() && ( (op.top()!='(' && Formula[p]==')') || (cmp(op.top(), Formula[p]))>0 ) && Formula[p]!='(') {
							int d = data.top();
							data.pop();
							if ( d==0 && (op.top()=='/' || op.top()=='%') ) {
								cout << "Divide 0." << endl;
								goto m;
							}
							else if ( d<0 && op.top()=='^' ) {
								cout << "error." << endl;
								goto m;
							}
							else clt(&data.top(), d, op.top());
							op.pop();
						}
					}
					if (Formula[p]==')' && op.size()==0) {
						cout << "error." << endl;
						goto m;
					}
					else    if (Formula[p]==')') {
								op.pop();
							}
							else {
								op.push(Formula[p]);
							}
				}
				p++;
			}
		}
		
		if (op.size()+1==data.size()) {
			while (op.size()) {
				int d = data.top();
				data.pop();
				if (d==0 && (op.top()=='/' || op.top()=='%')) {
					cout << "Divide 0." << endl;
					goto m;
				}
				else if ( d<0 && op.top()=='^' ) {
						cout << "error." << endl;
						goto m;
					}
				else clt(&data.top(),d,op.top());
				op.pop();
			}
			cout << data.top() << endl;
		}
		else cout << "error." << endl;
	
m:	;
	}
	 
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值