计算表达式的值

来源:互联网 发布:国际阿里云服务器购买 编辑:程序博客网 时间:2024/05/22 01:25

其中的 linkStack.h 的定义在 linkStack 博文里。

//用栈判断表达式是否合法,合法则计算,否则报错(不考虑除数为0的情况)/*程序包含的数学函数及替换字母:      函数名                       替换字母double sin(double x)                  'a'double cos(double x)                  'b'double tan(double x)                  'c'double asin(double x)                 'd'double acos(double x)                 'e'double atan(double x)                 'f'double sinh(double x)                 'g'double cosh(double x)                 'h'double tanh(double x)                 'i'double atan2(double x,double y)       'j'double fabs(double x)                 'k'double sqrt(double x)                 'l'double exp(double x)                  'm'double floor(double x)                'n'double log(double x)                  'o'double log10(double x)                'p'double pow(doublex,double y)          'q'这样做的优点:把数学函数转化成运算符,优先级高于'*'、'/',然后与运算符同等处理*/#include <iostream>#include <string>#include <cmath>#include "linkStack.h"    using namespace std;/*判断表达式是否合法1、缺少左括号,不指明位置(位置不确定)2、缺少右括号,不指明位置(位置不确定)3、出现非法字符,指明首位置4、缺少运算符,指明位置5、出现多余运算符,指明位置6、出现多余小数点,指明位置*/bool judge(string str){    linkStack<char> bracket;    bool flag=0;    //标记是否出现小数点    int i;    for(i=0;i<(int)str.length()-1;++i)    {        //str[i]为数字:若str[i-1]为右括号,报错"缺少运算符"        if(isdigit(str[i]))        {            if(str[i-1]==')')            {                cout<<"在第"<<i+1<<"个字符处缺少运算符!"<<endl;                return 0;            }        }        /*str[i]为小数点:若当前数字中已出现小数点或str[i-1]或str[i+1]不是          数字,报错"多余小数点"        */        else if(str[i]=='.')        {            if(flag||!isdigit(str[i-1])||!isdigit(str[i+1]))            {                cout<<"在第"<<i+1<<"个字符处出现多余小数点!"<<endl;                return 0;            }            flag=1;        }        //str[i]为'(':若str[i-1]为数字,报错"缺少运算符";否则入栈        else if(str[i]=='(')        {            if(isdigit(str[i-1]))            {                cout<<"在第"<<i+1<<"个字符处缺少运算符!"<<endl;                return 0;            }            bracket.push(str[i]);        }        /*str[i]为')':如果bracket栈为空,报错"缺少右括号";如果str[i-1]为          运算符,报错"多余运算符";否则出栈        */        else if(str[i]==')')        {            if(bracket.empty())            {                cout<<"表达式缺少左括号!"<<endl;                return 0;            }            else if(!isdigit(str[i-1])&&str[i-1]!=')')            {                cout<<"在第"<<i<<"个字符处出现多余运算符!"<<endl;                return 0;            }            else bracket.pop();            flag=0;        }        /*str[i]为字母:向后找出连续字母,判断是否为函数名,不是报错"不合法          字母";是函数名,判断前面是否为数字,是就报错"缺少运算符"        */        else if(islower(str[i]))        {            bool safe=0;            int pos=i;    //标记字母出现位置            string tmp="";            int len=-1;            for(;islower(str[i]);++i)            {                tmp+=" ",tmp[++len]=str[i];            }            if(len>=2&&len<=4)    //这里特别注意下标i的处理            {                if((tmp=="sin"||tmp=="cos"||tmp=="tan"||tmp=="asin"||                    tmp=="acos"||tmp=="atan"||tmp=="sinh"||tmp=="cosh"||                    tmp=="tanh"||tmp=="fabs"||tmp=="sqrt"||tmp=="exp"||                    tmp=="floor"||tmp=="log"||tmp=="pow")&&str[i]=='(')                 safe=1,--i;                if(tmp=="log"&&str[i]=='1'&&str[i+1]=='0'&&str[i+2]=='(')                 safe=1,++i;                if(tmp=="atan"&&str[i]=='2'&&str[i+1]=='(') safe=1;            }            if(!safe)            {                cout<<"在第"<<pos+1<<"个字符处出现非法字母!"<<endl;                return 0;            }            if(isdigit(str[pos-1]))            {                cout<<"在第"<<pos+1<<"个字符处缺少运算符!"<<endl;                return 0;            }        }        /*str[i]为运算符:i=0('+'、'-'除外)或str[i-1]不是数字,报错"多余运          算符"        */        else if(str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/')        {            bool safe=1;            if(str[i]=='+'||str[i]=='-')            {                if(i&&!isdigit(str[i-1])&&str[i-1]!='('&&str[i-1]!=')')                   safe=0;            }            else if(i==0||(!isdigit(str[i-1])&&str[i-1]!=')')) safe=0;            if(!safe)            {                cout<<"在第"<<i+1<<"个字符处出现多余运算符!"<<endl;                return 0;            }            flag=0;        }        //str[i]为其它非法字符:报错"非法字符"        else        {            cout<<"在第"<<i+1<<"个字符处出现非法字符!"<<endl;            return 0;        }    }    //遍历结束后,括号栈不为空,报错"缺少右括号"    if(!bracket.empty())    {        cout<<"表达式缺少右括号!"<<endl;        return 0;    }    return 1;}//用权值比较运算符优先级inline int val(char c){    int v;    if(c=='(') v=0;    //左括号为0    else if(c=='+'||c=='-') v=1;    //'+'、'-'为1    else if(c=='*'||c=='/') v=2;    //'*'、'/'为2    else v=3;    //数学函数为3    return v;}//将中缀表达式转化成后缀表达式并返回string convert(string str){    string tmp="";    //存储转换后的后缀表达式    int len=-1;    //tmp的下标    linkStack<char> oper;    //符号栈    for(int i=0;str[i]!='=';++i)    {        //str[i]为正号,跳过        if((i==0&&str[i]=='+')||(i&&str[i]=='+'&&str[i-1]=='(')) continue;        //str[i]为负号,用'#'代替并存入tmp        else if((i==0&&str[i]=='-')||(i&&str[i]=='-'&&str[i-1]=='('))         tmp+=" ",tmp[++len]='#';        //str[i]为数字或小数点,存入tmp        else if(isdigit(str[i])||str[i]=='.') tmp+=" ",tmp[++len]=str[i];        else        {            tmp+=" ",++len;    //保证每个运算数后都有空格            //str[i]为',',跳过            if(str[i]==',') continue;            //str[i]为'(',直接压栈            if(str[i]=='(') oper.push(str[i]);            //str[i]为')',不断出栈并将栈顶存入tmp,直到弹出'('(不存入tmp)            else if(str[i]==')')            {                while(oper.top()!='(')                {                    tmp+=" ",tmp[++len]=oper.pop();                }                oper.pop();            }            //str[i]为运算符            else            {                char temp;                /*str[i]为字母(函数名),把从i到'('前的字符存入func,将与func                  对应的字母(运算符)存入tmp                */                if(islower(str[i]))                {                    string func="";                    int cnt=-1;                    for(;str[i]!='(';++i)                    func+=" ",func[++cnt]=str[i];                    --i;                    if(func=="sin") temp='a';                    else if(func=="cos") temp='b';                    else if(func=="tan") temp='c';                    else if(func=="asin") temp='d';                    else if(func=="acos") temp='e';                    else if(func=="atan") temp='f';                    else if(func=="sinh") temp='g';                    else if(func=="cosh") temp='h';                    else if(func=="tanh") temp='i';                    else if(func=="atan2") temp='j';                    else if(func=="fabs") temp='k';                    else if(func=="sqrt") temp='l';                    else if(func=="exp") temp='m';                    else if(func=="floor") temp='n';                    else if(func=="log") temp='o';                    else if(func=="log10") temp='p';                    else if(func=="pow") temp='q';                }                else temp=str[i];                //如果符号栈为空,直接把temp压栈,continue                if(oper.empty())                {                    oper.push(temp);                    continue;                }                /*符号栈不为空,不断出栈并将栈顶存入tmp直到栈顶符号的权值                  小于str[i]的权值,把str[i]压栈                */                while(val(oper.top())>=val(temp))                {                    tmp+=" ",tmp[++len]=oper.pop();                    if(oper.empty()) break;                }                oper.push(temp);            }        }    }    tmp+=" ",++len;    //保证每个运算数后都有空格    //不断出栈并将栈顶存入tmp直到栈为空    while(!oper.empty())    {        tmp+=" ",tmp[++len]=oper.pop();    }    return tmp;}//计算中缀表达式str的值double calc(string str){    str=convert(str);    //调用convert函数将str转化成后缀表达式    linkStack<double> num;    //数字栈    double tmp=0;    //保存运算数    bool state=1;    //标记tmp的符号,1代表正,0代表负    double dec=1;    //用于处理小数位    bool flag=0;    //标记小数点是否出现    for(int i=0;i<(int)str.length();++i)    {        //str[i]为'#',state赋值为0,表示tmp为负        if(str[i]=='#') state=0;        //str[i]为数字,更新tmp值        else if(isdigit(str[i]))        {            //出现小数点后            if(flag) dec*=0.1,tmp=tmp+dec*(str[i]-'0');            //出现小数点前            else tmp=tmp*10+str[i]-'0';        }        //str[i]为小数点,flag赋值为1,表示当前运算数已出现小数点        else if(str[i]=='.') flag=1;        //str[i]为空格        else if(str[i]==' ')        {            //空格前为数字,将tmp值压栈,变量初始化(避免将多余的0压入数栈)            if(isdigit(str[i-1]))            {                if(!state) tmp=-tmp;                num.push(tmp);                tmp=0,state=1,dec=1,flag=0;            }        }        //str[i]为运算符,运算、压栈        else        {            double b=num.pop();            switch(str[i])            {                case 'a':num.push(sin(b));break;                case 'b':num.push(cos(b));break;                case 'c':num.push(tan(b));break;                case 'd':num.push(asin(b));break;                case 'e':num.push(acos(b));break;                case 'f':num.push(atan(b));break;                case 'g':num.push(sinh(b));break;                case 'h':num.push(cosh(b));break;                case 'i':num.push(tanh(b));break;                case 'j':num.push(atan2(num.pop(),b));break;                case 'k':num.push(fabs(b));break;                case 'l':num.push(sqrt(b));break;                case 'm':num.push(exp(b));break;                case 'n':num.push(floor(b));break;                case 'o':num.push(log(b));break;                case 'p':num.push(log10(b));break;                case 'q':num.push(pow(num.pop(),b));break;                case '+':num.push(num.pop()+b);break;                case '-':num.push(num.pop()-b);break;                case '*':num.push(num.pop()*b);break;                case '/':num.push(num.pop()/b);break;            }        }    }    return num.top();}