聪明的你帮助C小加解决了中缀表达式到后缀表达式的转换(详情请参考“郁闷的C小加(一)”),C小加很高兴。但C小加是个爱思考的人,他又想通过这种方法计算一个表达式的值。即先把表达式转换为后缀表达式,再求值。这时又要考虑操作数是小数和多位数的情况。
21+2=
(19+21)*3-4/5=
12+=
3.00
1921+3*45/-=
119.20
这是栈的经典题目,虽说并不难,还是有一些操作性,
这两道题卡了好久一直没做出来,主要是将后缀表达式建好,
考虑以下几种情况:
1.当前符号为(,那么直接入栈
2.当前符号为+ -,那么栈顶乘除出栈(如果有),然后判断
现在的栈顶是否为+ -,如果是入栈。(不能先出加减再出乘除,例如栈中是+*)
(23的当前符号都要入栈)
3.当前符号为* /,栈顶的乘除出栈
4.数字或小数点就全部就加入就行了。
5.当前符号为),和第2步一样。
这样后缀表达式出来就只要算出来就行了。
#include <stdio.h> #include <stack> #include <string.h> const int maxn = 10005; using namespace std; char str[maxn], suffix[maxn], tch[maxn]; int is_NumOrP ( char ch ) { return ch == '.' || ch >= '0' && ch <= '9'; } int is_opera ( char ch ) { return ch == '+' || ch == '-'; } int is_opers ( char ch ) { return ch == '*' || ch == '/'; } double to_Double ( char str[], int i, int j ) //转成小数 { int k; double ret = 0, b = 0.1; for ( k = i; k <= j; k ++ ) { if ( str[k] == '.' ) break ; ret = ret*10+( str[k]-'0' ); } k ++; while ( k <= j ) { ret += ( str[k]-'0' )*b; b *= 0.1; k ++; } return ret; } double opera ( double a, double b, char ch ) { switch ( ch ) //运算 { case '+' : return a+b; case '-' : return a-b; case '*' : return a*b; case '/' : return a/b; } return 0; } void print ( char str[] ) { int len = strlen ( str ); for ( int i = 0; i < len; i ++ ) if ( str[i] != ' ' ) printf ( "%c", str[i] ); puts ( "=" ); } int main ( ) { int T, pos, cas = 0; stack < double > val; stack < char > op; scanf ( "%d", &T ); while ( T -- ) { pos = 0; while ( ! val.empty ( ) ) val.pop ( ); while ( ! op.empty ( ) ) op.pop ( ); scanf ( "%s", str ); for ( int i = 0; str[i] != '='; i ++ ) { if ( str[i] >= '0' && str[i] <= '9' ) { while ( str[i] != '=' && is_NumOrP ( str[i] ) ) { suffix[pos ++] = str[i]; i ++; } suffix[pos ++] = ' '; i --; } else if ( str[i] == '(' ) op.push ( str[i] ); else if ( is_opers ( str[i] ) ) //乘除前面有乘除就将其放入后缀表达式 { if ( ! op.empty ( ) && is_opers ( op.top ( ) ) ) { suffix[pos ++] = op.top ( ); suffix[pos ++] = ' '; op.pop ( ); } op.push ( str[i] ); } else if ( is_opera ( str[i] ) ) { //加减前面有乘除就加入后缀 if ( ! op.empty ( ) && is_opers ( op.top ( ) ) ) { suffix[pos ++] = op.top ( ); suffix[pos ++] = ' '; op.pop ( ); } //去掉乘除(有) 前面一个是加减也将其加入后缀 if ( ! op.empty ( ) && is_opera ( op.top ( ) ) ) { suffix[pos ++] = op.top ( ); suffix[pos ++] = ' '; op.pop ( ); } op.push ( str[i] ); } else if ( str[i] == ')' ) { //注意最后一个可能是乘除 if ( ! op.empty ( ) && ( op.top ( ) == '*' || op.top ( ) == '/' ) ) { suffix[pos ++] = op.top ( ); suffix[pos ++] = ' '; op.pop ( ); } int cnt = 0; //前面实际上应该最多只有一个加减 while ( ! op.empty ( ) && op.top ( ) != '(' ) { tch[cnt ++] = op.top ( ); op.pop ( ); } if ( ! op.empty ( ) ) op.pop ( ); for ( int j = cnt-1; j >= 0; j -- ) //逆序 { suffix[pos ++] = tch[j]; suffix[pos ++] = ' '; } } } //最后栈中残余的符号,也要考虑最后一个乘除 if ( ! op.empty ( ) && ( op.top ( ) == '*' || op.top ( ) == '/' ) ) { suffix[pos ++] = op.top ( ); suffix[pos ++] = ' '; op.pop ( ); } int cnt = 0; while ( ! op.empty ( ) ) //这里其实最多也只有一个符号 { tch[cnt ++] = op.top ( ); op.pop ( ); } for ( int j = cnt-1; j >= 0; j -- ) { suffix[pos ++] = tch[j]; suffix[pos ++] = ' '; } suffix[pos] = '\0'; //puts ( suffix ); if ( cas ++ ) //控制换行 printf ( "\n" ); print ( suffix ); for ( int i = 0; i < pos; i ++ ) { if ( suffix[i] == ' ' ) //将空格continue continue ; if ( is_NumOrP ( suffix[i] ) ) { int j = i; while ( i < pos && is_NumOrP ( suffix[i] ) ) i ++; i --; val.push ( to_Double ( suffix, j, i ) ); } else { double b = val.top ( ); val.pop ( ); double a = val.top ( ); val.pop ( ); val.push ( opera ( a, b, suffix[i] ) ); } } printf ( "%.2lf\n", val.top ( ) ); } return 0; } /* 2 5-4+6/3*4= (5-(5-2*3+4))= */