基于栈的中缀算术表达式求值

基于栈的中缀算术表达式求值

描述

输入一个中缀算术表达式,求解表达式的值。运算符包括+、-、*、/、(、)、=,参加运算的数为double类型且为正数。(要求:直接针对中缀算术表达式进行计算,不能转换为后缀或前缀表达式再进行计算,只考虑二元运算即可。)

输入

多组数据,每组数据一行,对应一个算术表达式,每个表达式均以“=”结尾。当表达式只有一个“=”时,输入结束。参加运算的数为double类型。

输出

多组数据,每组数据一行,对应一个算术表达式,每个表达式均以“=”结尾。当表达式只有一个“=”时,输入结束。参加运算的数为double类型。

输入样例 1
2+2=
20*(4.5-3)=
=
输出样例 1
4.00
30.00
AC 代码
/*debug 近 4 个小时的血的教训:
1、不要使用 if (e) 和 if (!e) 这样花里胡哨的用法,
    或者说,现阶段为止,你必须用一次谨慎一次
2、不要迷信返回值,返回值不能给你过多的信息
3、需要理智去debug,比如这次里面,出现段错误,TLE和OLE,
    那么,很明显,这个是主函数出现错误
4、要自信
*/
#include <iostream>
#include <algorithm>

#define MAX 100

using namespace std;

typedef struct
{
    double *base;
    double *top;
    int maxSize;
}stack1;

void initStack1(stack1 &s)
{
    s.base = new double [MAX];
    if(!s.base)
        cout << "分配空间错误" << endl;
        
    s.top = s.base;
    s.maxSize = MAX;
}

void push1(stack1 &s, double e)
{
    if (s.top - s.base == s.maxSize)
        cout << "栈已满,无法添加" << endl;

    *s.top = e;
    s.top ++;
}

void pop1(stack1 &s)
{
    if (s.top == s.base)
        cout << "栈已空,无法删除" << endl;
        
    s.top --;
}

double top1(stack1 s)  
{
    if (s.top == s.base)
        cout << "栈已空,无法取值" << endl;

    return *(s.top - 1);
}

typedef struct
{
    char *base;
    char *top;
    int maxSize;
}stack2;

void initStack2(stack2 &s)
{
    s.base = new char [MAX];
    if (!s.base)
        cout << "分配空间错误" << endl;

    s.top = s.base;
    s.maxSize = MAX;
}

void push2(stack2 &s, char e)
{
    if (s.top - s.base == s.maxSize)
        cout << "栈已满,无法添加" << endl;

    *s.top = e;
    s.top ++;
}

void pop2(stack2 &s)
{
    if (s.top == s.base)
        cout << "栈已空,无法删除" << endl;        

    s.top --;
}

char top2(stack2 s)
{
    if (s.top == s.base)
        cout << "栈已空,无法取值" << endl;

    return *(s.top - 1);
}

char pre(char a,char b)                         // 记住表即可,深入理解
{
	if((a=='('&&b==')')||(a=='='&&b=='='))
		return '=';
	else if(a=='('||a=='='||b=='('||(a=='+'||a=='-')&&(b=='*'||b=='/'))
		return '<';
	else
		return '>';
}

double cal(double a, double b, char op)         // 注意 b 和 a应该反一下,因为栈的特性
{
    if (op == '+')
        return b + a;
    else if (op == '-')
        return b - a;
    else if (op == '*')
        return b * a;
    else 
        return b / a;
}

int main()
{
    string s;
    while (cin >> s && s[0] != '=')
    {
        stack1 ds;
        initStack1(ds);
        stack2 cs;
        initStack2(cs);
        
        push2(cs, '=');
        
        int x = 0, e = 0, flag = 0;
        /*基本思路:
        我们对于单个数字字符,先不进行push,而是等到下一个运算字符
        出现,我们通过判断来获得运算字符前面的几个数字字符构成的double类
        数字
        由于本题中每一次循环,都有可能有特例和上一次循环有联系
        因此,我们采用 flag 法,进行标记处理
        */
        for (int i = 0; s[i] != '\0'; i ++) 
        {
            if ('0' <= s[i] && s[i] <= '9')
            {
                flag = 1;
                x = x * 10 + (s[i] - '0');
                if (e != 0)
                    e *= 10;
            }
            else if (s[i] == '.')
                e = 1;
            else
            {
                if (flag != 0)
                {
                    double number = x;
                    if (e != 0)
                        number /= e;
                    push1(ds, number);
                    x = flag = e = 0;
                }
                while (1)
                {
                    if (pre(top2(cs), s[i]) == '<')
                    {
                        push2(cs, s[i]);
                        break;
                    }
                    else if (pre(top2(cs), s[i]) == '>')
                    {
                        double a = top1(ds);
                        pop1(ds);
                        double b = top1(ds);
                        pop1(ds);
                        
                        char op = top2(cs);
                        pop2(cs);
                        push1(ds, cal(a, b, op));
                    }
                    else
                    {
                        pop2(cs);
                        break;
                    }
                }
            }            
        }
        printf("%.2lf\n", top1(ds));
    }
    return 0;
}
上一篇:汇编语言.实验2


下一篇:实验2 多个逻辑段的汇编源程序编写与调试