这个和从前我写过的不太一样。从前是把不同的运算符分不同的优先级,入栈的时候根据优先级来判断进出。下面的代码是直接入栈的时候根据栈顶运算符来判断当前运算符入栈与否。
当前运算符是+-=时,那么如果栈顶元素不为(,就一定要进行运算,把前边排的都算完了(算到左括号或空为止),才能入栈(=不用入栈,直接出结果)
如果是*/,那么只能算完栈顶元素是*/的情况,如果是+-之类的,就不能继续算了,因为乘除优先级高,
如果是(,那么不管三七二十一,直接入栈,
如果是),就一直进行计算,直到栈顶元素是(,这时候括号内的内容算完了,然后把左括号出栈就好了。右括号不需要入栈
/* nyoj-35 表达式计算(中缀式求值)
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stack>
#define N 1050
using namespace std;
char s[N];
stack<double>Num; // 数据栈
stack<char>Ope; // 符号栈
double JiSuan(){ // 计算函数,自身从栈中取数据
double b = Num.top();
Num.pop();
double a = Num.top();
Num.pop();
char c = Ope.top();
Ope.pop();
switch(c){
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
return a / b;
}
}
double JieXi(){ // 解析函数
int i = -1, ni = 0; // i为输入表达式(字符串)下标 ,ni为num数组下标;
char num[100] = {"\0"}; // 暂存数字字符和小数点,用于将字符串转换为数字
double ans = 0; // 记录每一次计算的结果
while(1){
i ++;
if(isdigit(s[i]) || s[i] == '.'){ // 如果当前字符是数字或小数点,将其直接放入数字暂存数组
num[ni ++] = s[i];
}
else{ // 当前字符为运算符
if(ni != 0){ // 如果数字暂存数组中有数据,转换成数字,并压入数据栈
sscanf(num, "%lf", &ans);
Num.push(ans);
memset(num, '\0', sizeof(num)); // 入栈后清空暂存数组,其下标置零
ni = 0;
}
switch(s[i]){ // 分析运算符,并开始计算
case '+':
case '-':
case '=':
while(!Ope.empty() && Ope.top() != '('){ // 其它运算符优先级都高于+、-、=,先全部运算直至符号栈栈顶为'('或栈空
ans = JiSuan();
Num.push(ans); // 记得将运算结果压入数据栈,当前运算符break后压入
}
break;
case '*':
case '/':
while(!Ope.empty() && (Ope.top() == '*' || Ope.top() == '/')){
ans = JiSuan();
Num.push(ans);
}
break;
case ')':
while(Ope.top() != '('){ // 运算直至符号栈栈顶为(
ans = JiSuan();
Num.push(ans);
}
Ope.pop(); // 将栈顶的(弹出
break;
case '(': // ( 之后直接如符号栈即可,无需运算
break;
}
if(s[i] == '='){
Num.pop(); // 此次弹出后,数据栈已清空;并且在之前运算中符号栈已清空(有运算符就有运算)
break; // 运算结束
}
else{
if(s[i] != ')'){ // )、=不入栈,其余运算符都入栈
Ope.push(s[i]);
}
}
}
}
return ans;
}
int main()
{
int loop;
scanf("%d", &loop);
while(loop --){
scanf(" %s", s);
double ans = JieXi();
printf("%.2lf\n", ans);
}
return 0;
}