NYOJ 35 表达式求值 or 267 郁闷的C小加(二)

描述

聪明的你帮助C小加解决了中缀表达式到后缀表达式的转换(详情请参考“郁闷的C小加(一)”),C小加很高兴。但C小加是个爱思考的人,他又想通过这种方法计算一个表达式的值。即先把表达式转换为后缀表达式,再求值。这时又要考虑操作数是小数和多位数的情况。

输入
第一行输入一个整数T,共有T组测试数据(T<10)。
每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式,每个运算式都是以“=”结束。这个表达式里只包含+-*/与小括号这几种符号。其中小括号可以嵌套使用。数据保证输入的操作数中不会出现负数并且小于1000000。
数据保证除数不会为0。
输出
对于每组测试数据输出结果包括两行,先输出转换后的后缀表达式,再输出计算结果,结果保留两位小数。两组测试数据之间用一个空行隔开。
样例输入
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))=
*/



你可能感兴趣的:(NYOJ 35 表达式求值 or 267 郁闷的C小加(二))