逆波兰表达式及求值

逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。逆波兰表达式又叫做后缀表达式。这个知识点在 数据结构和编译原理这两门课程中都有介绍,下面是一些例子:
正常的表达式 逆波兰表达式
a+b ---> a,b,+
a+(b-c) ---> a,b,c,-,+
a+(b-c)*d ---> a,b,c,-,d,*,+
a+d*(b-c)--->a,d,b,c,-,*,+
a=1+3 ---> a=1,3 +
逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。
例如
(a+b)*(c+d) 转换为 ab+cd+*
 
下面是程序化算法流程:
1、建立 运算符栈stackOperator用于运算符的存储,压入'\0'。
2、预处理表达式,正、负号前加0(如果一个加号(减号)出现在最前面或左括号后面,则该加号(减号)为正负号) 。
3、顺序扫描表达式,如果当前字符是数字(优先级为0的符号),则直接输出该数字;如果当前字符为运算符或括号(优先级不为0的符号),则判断第4点 。
4、若当前运算符为'(',直接入栈;
若为')', 出栈并顺序输出 运算符直到遇到第一个'(',遇到的第一个'(' 出栈但不输出;
若为四则运算符,比较栈顶元素与当前元素的优先级:
如果 栈顶元素运算符优先级 >= 当前元素的优先级, 出栈并顺序输出运算符直到 栈顶元素优先级 < 当前元素优先级,然后当前元素入栈;
如果 栈顶元素 < 当前元素,直接入栈。
5、重复第3点直到表达式扫描完毕。
6、顺序出栈并输出 运算符直到栈顶元素为'\0'。
 
#include <iostream>
#include <set>
#include <vector>
#include <map>
#include <list>
#include <math.h>
#include <stack>
using namespace std;
enum tErroCode{
    kErrorCode_NoError ,
    kErrorCode_DevideByZero,
    kErrorCode_InvalitExpressionFound ,
};
int     Precedence(char sign);
void    makePostfixExpr(const char* exp,vector<string> &vec);
double  str2double(const string &str);
double  PostfixExprCalculation(vector<string> &vec, tErroCode &errorCode);
bool    LegitimacyDetection(const char* pszCalcExpr);
double  Calculate( const char* pszCalcExpr, tErroCode &errorCode );
void print(vector<string> &vec){
    for(int i=0;i<vec.size();++i){
        cout<<vec[i]<<" ";
    }
    cout<<endl;
}
/*  Note:
*   1. we assume the following cases are legal
*       a.  1 2 + 3 34      is equivalent to 12+334
*       b.  -1 + -2 / -3    is equivalent to (-1)+(-2)/(-3)
*           1 + -2          is equivalent to 1+(-2)
*           while -1 + *2 / +3 is illegal, because *2 and +3 are illegal, we can change the code in function Str2Double() to make +3 legal
*       c.  . + 1           is equivalent to 0.0 + 1        also .1 and 1. equal 0.1 and 1.0 , they are both legal
*
*/
double  Calculate( const char* pszCalcExpr, tErroCode & errorCode )
{
    if(!LegitimacyDetection(pszCalcExpr)){
        errorCode = kErrorCode_InvalitExpressionFound ;
        return 0;
    }
    /*
    *record postfix expression
    */
    vector<string> vec;
    /*
    *   change the expression to Postfix expression
    *    for instance ((1+(2+3)/4)/ -5 )/ -6  ->  1 2 3 + 4 / + (-5) / (-6) /
    */
    makePostfixExpr(pszCalcExpr,vec);
//    print(vec);
    /*
    *Calculate the postfix expression
    */
    return PostfixExprCalculation(vec, errorCode);
}
int main()
{
    freopen("in.txt","r",stdin);
    char exp[1000];
    tErroCode ec;
    while(cin.getline(exp,1000)){
//        cout<<exp<<endl;
        printf("%.2lf %d\n",Calculate(exp,ec),ec);
        ec=kErrorCode_NoError ;
    }
    return 0;
}
int Precedence(char sign)
{
    switch(sign)
    {
        case '+':
        case '-':
            return 1;

        case '*':
        case '/':
            return 2;
        case '^':
        case '%':
            return 3;

        case '(':
        case ')':
            return -1;

        default:
            return 0;
    }
}
bool LegitimacyDetection(const char* pszCalcExpr){

    /*Illegal case:
    *   1. Mismatched of '(' and ')',  like (1+2, 1+(3-(4/5)... are illegal
    *   2. we put other detections in function  PostfixExprCalculation() and str2double(), like 1/0, 1+2+*3, *1+/2 ...  are illegal
    *   note: we assume space appear in the middle of an Operand is legal, like 1 2 + 3 equals to  12+3 and the result is 15, and .+1 equals 0.0+1=1.0
    */

    // 1. Mismatched of '(' and ')'
    stack<char> stk;
    int i,len=strlen(pszCalcExpr),ret;
    for(i=0;i<len;++i){
        if(pszCalcExpr[i]=='('){
            stk.push('(');
        }else if(pszCalcExpr[i]==')'){
            if(!stk.empty())
                stk.pop();
            else {
                return false;
            }
        }
    }
    if(!stk.empty()) return false;
    return true;
}

void makePostfixExpr(const char* exp,vector<string> &vec){
    stack<char> stk;
    stk.push('#');
    int len=strlen(exp);
    int p=0,ret;
    string op=" ";
    char pre_oper=' ';
    /* 1. We split the expression into the form : Operand, Operator, Operand, ... Operator, Operand
    *   for example
    *       1 + 2 + 3       ->  1, +, 2 , +, 3
    *       1 + (2 + 3)     ->  1, +, ( , 2, + , 3, )
    *       1 -/ 2 +* 3     ->  1, -, /2, +, *3     Apparently /2 and *3 are illegal operand, we check them in the function Str2Double()
    *       1 / -2 + 3      ->  1, /, -2, +, 3      -2 is a legal operand
    *
    *  2. After split the expression we change the expression to postfix expression
    *
    */
    while(p<len){
        double x=0;
        bool tag=false;
        string num="";
        while(exp[p]==' ')++p;// skip the space
        if(pre_oper!=')'){
            while(p<len&&(Precedence(exp[p])==1||Precedence(exp[p])==2)){
                if(exp[p]!=' '){
                    num+=exp[p];
                    tag=true;
                }
                ++p;
            }
        }
        while(p<len&&Precedence(exp[p])==0){
            if(exp[p]!=' '){
                num+=exp[p];
                tag=true;
            }
            ++p;
        }
        if(tag){
            vec.push_back(num);
        }
        if(p==len)break;
        ret=Precedence(exp[p]);
        // when the Operator is '(' push into the stack, if the operator is ')' pop the operators in the stack until reach '('
        if(ret==-1){
            if(exp[p]=='('){
               stk.push(exp[p]);
            }else{
                while(stk.top()!='('){
                    op[0]=stk.top();
                    vec.push_back(op);
                    stk.pop();
                }
                stk.pop(); // pop the operator '('
            }
        }else {
            // pop the operators in the stack until the operator on the top of stack has lower priority than the current operator
            while(Precedence(stk.top())>=ret){
                op[0]=stk.top();
                vec.push_back(op);
                stk.pop();
            }
            stk.push(exp[p]);
        }
        pre_oper=exp[p];
        ++p;
    }
    while(stk.top()!='#'){
        op[0]=stk.top();
        vec.push_back(op);
        stk.pop();
    }
}
double str2double(const string &str,tErroCode & errorCode){
    //include dot operator, like 1.23
    double sig=1,ret=0,n=10;
    int len = str.length(),i,dot=str.find('.');
    if(dot==-1)dot=len;
    if(str[0]=='-'){
        i=1;
        sig=-1;
    }
    /*
    *   if an operand with prefix '+' is legal ,like +3
    *   then uncomment the following code
    */
//    else if(str[0]=='+'){
//        i=1;
//        sig=1;
//    }
    else i=0;
    for(;i<dot;++i){
        if(!(str[i]>='0'&&str[i]<='9')){
            errorCode = kErrorCode_InvalitExpressionFound ;
            return 0;
        }
        ret=ret*10+str[i]-'0';
    }
    for(i=dot+1;i<len;++i){
        ret=ret+(str[i]-'0')/n;
        n*=10;
    }
    return ret*sig;
}
double PostfixExprCalculation(vector<string> &vec, tErroCode & errorCode){

    stack<double> stk;
    int i,len=vec.size();
    string str;
    for(i=0;i<len;++i){
        str=vec[i];
        // operator
        if(Precedence(str[0])>0&&str.length()==1){
            double x,y;
            if(stk.size()<2){
                errorCode=kErrorCode_InvalitExpressionFound ;
                return 0;
            }
            y=stk.top();stk.pop();
            x=stk.top();stk.pop();
            switch(str[0]){
                case '+':
                    x+=y;
                    break;
                case '-':
                    x-=y;
                    break;
                case '*':
                    x*=y;
                    break;
                case '^':
                    x=pow(x,y);
                    break;
                case '%':
                    if(y==0){
                        errorCode=kErrorCode_DevideByZero;
                        return 0;
                    }
                    x=(int)x%(int)y;
                    break;
                case '/':
                    if(y==0){
                        errorCode=kErrorCode_DevideByZero;
                        return 0;
                    }
                    x/=y;
                    break;
            }
            stk.push(x);
        }else{                              //operand
            double tmp= str2double(str,errorCode);
            if(errorCode != kErrorCode_InvalitExpressionFound ){
                stk.push(tmp);
            }else {
                return 0;
            }
        }
    }
    if(stk.empty()||stk.size()>1){
        errorCode = kErrorCode_InvalitExpressionFound ;
        return 0;
    }
    errorCode=kErrorCode_NoError;
    return stk.top();

}




 
 
 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值