存在空格的表达式求值


时间限制: 3000 ms  |  内存限制: 65535 KB
难度: 4
描述
ACM队的mdd想做一个计算器,但是,他要做的不仅仅是一计算一个A+B的计算器,他想实现随便输入一个表达式都能求出它的值的计算器,现在请你帮助他来实现这个计算器吧。
比如输入:“1+2/4=”,程序就输出1.50(结果保留两位小数)
输入
第一行输入一个整数n,共有n组测试数据(n<10)。
每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式,每个运算式都是以“=”结束。这个表达式里只包含+-*/与小括号这几种符号。其中小括号可以嵌套使用。数据保证输入的操作数中不会出现负数。
数据保证除数不会为0.

 

 

这是我们oj的一道题,但是它非常有局限性,就是当表达式中间存在空格的时候,如何正常计算表达式的值。

 

无法克服表达式中有空格的程序:


#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include<stack>
#include<string.h>
using namespace std;
bool IsOperator(char ch);
char Precede(char opr1, char opr2);
double Operate(double opnd1, char op, double opnd2);
int ConvertToIndex(char opr);
/**
  这个是用来判断一个字符是不是
  操作符的
*/
bool IsOperator(char ch)
{
    if (ch == '+' || ch == '-' ||
            ch == '*' || ch == '/' ||
            ch == '(' || ch == ')' || ch == '=')
        return true;
    else
        return false;

}

//运算符的优先关系
//'+', '-', '*', '/', '(', ')', '#'
char OprRelation[7][7] = {{'>', '>', '<', '<', '<', '>', '>'}, //'+'
    {'>', '>', '<', '<', '<', '>', '>'}, //'-'
    {'>', '>', '>', '>', '<', '>', '>'}, //'*'
    {'>', '>', '>', '>', '<', '>', '>'}, //'/'
    {'<', '<', '<', '<', '<', '=', ' '}, //'('
    {'>', '>', '>', '>', ' ', '>', '>'}, //')'
    {'<', '<', '<', '<', '<', ' ', '='}
};//'#'
/**
   这个是用来获取每一个操作符的优先级
*/
int ConvertToIndex(char opr)
{
    int index;

    switch (opr)
    {
    case '+':
        index = 0;
        break;
    case '-':
        index = 1;
        break;
    case '*':
        index = 2;
        break;
    case '/':
        index = 3;
        break;
    case '(':
        index = 4;
        break;
    case ')':
        index = 5;
        break;
    case '=':
        index = 6;
        break;
    }

    return index;
}
/**
   这个是用来获取连个字符的优先级
*/
char Precede(char opr1, char opr2)
{
    int index1 = ConvertToIndex(opr1);
    int index2 = ConvertToIndex(opr2);

    return OprRelation[index1][index2];
}
/**
    这个是用来对两个数进行求值
*/
double Operate(double opnd1, char op, double opnd2)
{
    double ret;

    switch(op)
    {
    case '+':
        ret = opnd1 + opnd2;
        break;
    case '-':
        ret = opnd1 - opnd2;
        break;
    case '*':
        ret = opnd1 * opnd2;
        break;
    case '/':
        ret = opnd1 / opnd2;
        break;
    }

    return ret;
}

//算符优先算法
double CaculateExpression(string exp)
{
    stack<char> optr; //只处理+ - # / ()运算
    stack<double> opnd;  //只处理0-9的整数运算
    char ch;
    int i = 0;
    optr.push('=');
    ch = exp[i++];
    bool flag = true;
    //如果##配对,表达式求值完成
    while (flag&&(ch != '=' || optr.top() != '='))
    {
        if (!IsOperator(ch))
        {
            string f,g;
            f=exp[i-1];
            g.append(f);
            while(!IsOperator(exp[i]))
            {
                f=exp[i];
                g.append(f);
                ++i;
            }
            double value = atof(g.c_str());
            //操作数入栈
            opnd.push(value);
            ch = exp[i++];
        }
        else
        {
            //比较栈顶操作符和新取得的操作符的优先关系
            cout<<optr.top()<<"   "<<ch<<endl;
            cout<<Precede(optr.top(),ch)<<endl;
            switch (Precede(optr.top(), ch))
            {
            case '<'://栈顶优先权低
                optr.push(ch);
                ch = exp[i++];
                break;
            case '='://括号配对,栈顶括号弹出
                optr.pop();
                if(exp.length()==i)
                {
                    flag=false;
                }
                else
                {
                    ch = exp[i++];
                }
                break;
            case '>'://栈顶优先权高,先弹出,计算,结果操作数入栈
                char op = optr.top();
                optr.pop();
                double num2 = opnd.top();//第二个操作数在前
                opnd.pop();
                double num1 = opnd.top();
                opnd.pop();

                double ret = Operate(num1, op, num2);

                opnd.push(ret);
                break;
            }
        }
    }//end of while
//    cout<<ch<<"   "<<optr.top()<<endl;

    //操作数栈的唯一元素即为计算结果
    return opnd.top();
}


int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        char str[1000];
        scanf("%s",str);
        // strcat(str,"#");
        string f;
        f=str;
        //cout<<atof(f.c_str())<<endl;
        printf("%.2lf\n",CaculateExpression(f));

    }
    return 0;
}

 

克服表达式中有空格的程序:

#include<stdio.h>
#include<string>
#include<string.h>
#include<iostream>
#include<stack>
#include<stdlib.h>
using namespace std;
stack<double> num;
stack<char> optr;
//                 +   -   *   /   (   )  =
char opt[7][7]= {'>','>','<','<','<','>','>', // +
                 '>','>','<','<','<','>','>',// -
                 '>','>','>','>','<','>','>',// *
                 '>','>','>','>','<','>','>',// /
                 '<','<','<','<','<','=','>',// (
                 '>','>','>','>','>','>','>', // )   // 不可能放进去的
                 '<','<','<','<','<','<','=' // =
                };
double rel_two(double a,char b,double c)
{
    switch(b)
    {
    case '+':
        return a+c;
    case '-':
        return a-c;
    case '*':
        return a*c;
    case '/':
        return a/c;
    }
}
bool is_optr(char& ch)
{
    if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='=')
    {
        return true;
    }
    else
        return false;

}
int pri(char _pri)
{
    switch(_pri)
    {
    case '+':
        return 0;
    case '-':
        return 1;
    case '*':
        return 2;
    case '/':
        return 3;
    case '(':
        return 4;
    case ')':
        return 5;
    case '=':
        return 6;

    }
}
char priority(char a,char b)
{
    int a1,b1;
    a1=pri(a);
    b1=pri(b);
    return opt[a1][b1];

}
double cal(string exp)
{
    optr.push('=');
    int i=0;
    char ch=exp[i++];
    while((optr.top()!='=' || ch!='=' )&& ch!='\0')
    {
        if(ch!=' ')
        {
            if(is_optr(ch))
            {
//                cout<<ch<<endl;
 cout<<optr.top()<<"     "<<ch<<endl;
 cout<<priority(optr.top(),ch)<<endl;
                switch(priority(optr.top(),ch))
                {

                case '<':
                    optr.push(ch);
//                    cout<<optr.top()<<"     "<<ch<<endl;
                    ch=exp[i++];
                    break;
                case '=':
                    optr.pop();
                    ch=exp[i++];
                    break;
                case '>':
                    char ch1;
                    ch1=optr.top();
//                    cout<<ch1<<endl;
                    optr.pop();
                    double a,b;
                    b=num.top();
                    num.pop();
                    a=num.top();
//                    cout<<a<<b<<endl;
                    num.pop();
                    num.push(rel_two(a,ch1,b));
//                    cout<<num.top()<<endl;
//                    ch=exp[i++];  //  栈顶元素需要依次和ch比较优先级
                    break;

                }

            }
            else
            {
                string p,q;
                q=ch;
                p.append(q);
//                while(!is_optr(ch)&&ch!=' ')
                while(!is_optr(exp[i])&&exp[i]!=' ')
                {
//                    q=exp[i];               // error occur!
                    p.append(q);
                    i++;
                }
//                cout<<p<<endl;
                ch=exp[i++];
                num.push(atof(p.c_str()));
//                cout<<atof(p.c_str())<<endl;
//                cout<<p<<endl;

            }

        }
        else
        {
            ch=exp[i++];
        }
    }

    return num.top();
}
int main()
{
    int n;
    scanf("%d",&n);
    getchar();
    while(n--)
    {
        char s[100];
        gets(s);
        string s1;
        s1=s;
//        cout<<s<<endl;
//        cout<<atoi(s1.c_str())<<endl;
        cout<<cal(s1.c_str())<<endl;
    }

}


输出结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿的探索之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值