一、题目描述
背景:
我们的教材中已经介绍了表达式求值的算法,现在我们将该算法的功能进行扩展,要求可以处理的运算符包括:+、-、*、/、%(整数取余)、^(乘方)、(、)。
要求:
采用算符优先算法,计算的中间结果只保留整数。
输入:
第一行为整数N。表示下面有N个表达式
从第二行起的后面N行为N个由整数构成的表达式
输出:
共N行,每行为相应表达式的计算结果。
如果判断出表达式有错误,则输出:error.
如果在计算过程中出现除数为0的情况,则输出:Divide 0.
特殊情况说明:
在表达式中,如果操作数出现负数(例如-8),则要特别注意。例如:
10加-8表示为:10+-8。
10减-8表示为:10--8。
测试输入 期待的输出 时间限制 内存限制 额外进程 测试用例 1 以文本方式显示
- 4↵
- 2^3↵
- 2^0↵
- 2^3^2↵
- 2^(3-1)^(10-8)↵
以文本方式显示
- 8↵
- 1↵
- 512↵
- 16↵
1秒 64M 0
测试用例 2 以文本方式显示
- 11↵
- (2+8↵
- 2+8)↵
- 8/0↵
- 8/(8+5-13)↵
- 2^(2-5)↵
- 10-(80-30(/3*3+4↵
- 10-80-30)/3*3+4↵
- (2+8)(3+2)↵
- (2)3(8)↵
- 30(/3+3)+4↵
- 10(20-8)+2↵
以文本方式显示
- error.↵
- error.↵
- Divide 0.↵
- Divide 0.↵
- error.↵
- error.↵
- error.↵
- error.↵
- error.↵
- error.↵
- error.↵
1秒 64M 0
测试用例 3 以文本方式显示
- 2↵
- 10(10)↵
- 14*10-(10)2↵
以文本方式显示
- error.↵
- error.↵
1秒 64M 0
测试用例 5 以文本方式显示
- 14↵
- 18-32↵
- 18/4↵
- 18%3↵
- 10+20*4↵
- 10-20/4↵
- (18-3)*3↵
- 10*(10)↵
- (10+2)/(8-10)↵
- (2*3)/(5*2)↵
- 10-(80-30)/3*3+4↵
- (((2+8)*2-(2+4)/2)*2-8)*2↵
- (((8+2)*(4/2)))↵
- 10/0↵
- (10-80*2↵
以文本方式显示
- -14↵
- 4↵
- 0↵
- 90↵
- 5↵
- 45↵
- 100↵
- -6↵
- 0↵
- -34↵
- 52↵
- 20↵
- Divide 0.↵
- error.↵
1秒 64M 0
二、操作的注意点
使用栈来处理表达式,具体的操作过程就不多说了,基础中的基础。
说几个我在写的过程中遇到的问题吧,提醒下同学们(或者学弟学妹们)。
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;
}