1. 程式人生 > >NYOJ 35 表示式求值 (中綴表示式 小數 帶括號)

NYOJ 35 表示式求值 (中綴表示式 小數 帶括號)

表示式求值

時間限制:3000 ms  |  記憶體限制:65535 KB 難度:4
描述
ACM隊的mdd想做一個計算器,但是,他要做的不僅僅是一計算一個A+B的計算器,他想實現隨便輸入一個表示式都能求出它的值的計算器,現在請你幫助他來實現這個計算器吧。
比如輸入:“1+2/4=”,程式就輸出1.50(結果保留兩位小數)
輸入
第一行輸入一個整數n,共有n組測試資料(n<10)。
每組測試資料只有一行,是一個長度不超過1000的字串,表示這個運算式,每個運算式都是以“=”結束。這個表示式裡只包含+-*/與小括號這幾種符號。其中小括號可以巢狀使用。資料保證輸入的運算元中不會出現負數。
資料保證除數不會為0
輸出
每組都輸出該組運算式的運算結果,輸出結果保留兩位小數。
樣例輸入
2
1.000+2/4=
((1+2)*5+1)/4=
樣例輸出
1.50
4.00

AC程式碼:

#include <stdio.h>
#include <stack>
#include <stdlib.h>
#include <ctype.h>
using namespace std;
int pre(char c)
{
if(c=='=') return 0;
else if(c=='+'||c=='-') return 1;
else if(c=='*'||c=='/') return 2;
return 0;
}
void answer(stack<double> &num,stack<char> &op)
{
double b=num.top();
num.pop();
double a=num.top();
num.pop();
switch(op.top())
{
case '+':num.push(a+b);break;
case '-':num.push(a-b);break;
case '*':num.push(a*b);break;
case '/':num.push(a/b);break;
}
op.pop();
}
int main()
{
stack<double> num;//儲存數字 
stack<char> op;//儲存操作符 
char s[1005];
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",s);
for(int i=0;s[i]!='\0';i++)
{
if(isdigit(s[i]))//判斷這個字元是不是數字 
{
double temp=atof(&s[i]);
//將這串字元轉化成對應的數字,直到遇到不是數字或小數點為止 
num.push(temp);
while(isdigit(s[i])||s[i]=='.')
i++;
i--;
}
else//這個字元是操作符 
{
if(s[i]=='(') op.push(s[i]);//是左括號 
else if(s[i]==')')//是右括號 
{
while(op.top()!='(')
answer(num,op);
op.pop();//把( 移出棧 
}
//是優先順序大於棧頂的操作符,或棧為空,直接進棧 
else if(op.empty()||pre(s[i])>pre(op.top()))
op.push(s[i]);
//是優先順序不大於棧頂的操作符,且棧不空,先進行運算操作
//直到不符合上述條件為止,然後該操作符進棧 
else if(!op.empty()&&pre(s[i])<=pre(op.top()))
{
while(!op.empty()&&pre(s[i])<=pre(op.top()))
answer(num,op);
op.push(s[i]);//將優先順序大於它的操作做完再讓它進棧 
}
}
}
printf("%.2lf\n",num.top());//留在數字棧內的棧頂就是結果 
num.pop();//結果出棧 
op.pop();//等號出棧 
//以上兩部清空了棧 
}
return 0; 
}