表达式求值——栈模拟

表达式求值,学数据结构时的经典无问题。

以前把严蔚敏那本数据结构书上的例子都打了一遍,后来硬盘坏了就丢了,还有点小心痛,

今天学妹让我帮她写段,于是花了大半个小时就有了这一段,

首先先构思:

对于一个表达式字符串呢,机器是不认识的,所以我们要把字符串解析出来,依此的把数字放在数字栈中,符号放在符号栈中,由于老师要求不能用stack 于是就有了我自己定义的栈(只定义了计算中需要的几个函数):

<span style="font-size:18px;">template<class T>
class STACK{
private:
    int p;
    int msize;
    T*  mdate;

public:
    STACK(){    //构造函数,申请栈空间
        p=-1;
        msize=50;
        mdate= (T*)malloc(sizeof(T)*50);
    }
    void push(T elem){  //插入元素
        if(p==msize-1){
            mdate=(T*)realloc(mdate, 20*sizeof(T) );
            msize += 20;
        }
        mdate[++p] =elem;
    }

    bool isempty(){  //判断栈是否为空
        return p==-1;
    }

    void pop(){    //删除元素
        if(isempty() )
            exit(1);
        --p;
    }

    T top(){  //返回栈顶元素
        return mdate[p];
    }

};</span>

上面就是栈的代码了 ,应为既要用到符号类型的栈,又要用到数字类型的栈,所以定义为泛型,

接下来就该是运算了:

四则运算的规则为:

  1. 先乘除,后加减,
  2. 从左到右
  3. 先括号内,后括号外
表达式由 操作数, 运算符,界限符(#)构成,后两者统称为算符,算符是有优先级的的,从四则运算规则就能看出,分别为'>','<','=',下面是算符优先关系表:

                                

运算的具体过程不多说,可以参照严蔚敏的数据结构查看,

直接贴代码段,再解释一下要注意的地方吧(我假设你输入都是合法的):

char getOperation(char c, char e){  //操作表
    char ope[7][7]={{'>','>','<','<','<','>','>'},
                    {'>','>','<','<','<','>','>'},
                    {'>','>','>','>','<','>','>'},
                    {'>','>','>','>','<','>','>'},
                    {'<','<','<','<','<','=',' '},
                    {'>','>','>','>',' ','>','>'},
                    {'<','<','<','<','<',' ','='}
                    };
    int i,j;
    if(c=='+') i=0;if(c=='-') i=1;if(c=='*') i=2;
    if(c=='/') i=3;if(c=='(') i=4;if(c==')') i=5;
    if(c=='#') i=6;
    if(e=='+') j=0;if(e=='-') j=1;if(e=='*') j=2;
    if(e=='/') j=3;if(e=='(') j=4;if(e==')') j=5;
    if(e=='#') j=6;
    return ope[i][j];
}

template<class T1>  //读取字符串中的数字
int addunm(string str, STACK<T1> &num, int i){
    int step=1;
    num.push(str[i++]-'0');
    while( str[i]<=57 && str[i]>=48 ){  //小数点前部分
        double tmp=num.top();
        num.pop();
        num.push(tmp *10 + (str[i]-'0'));
        i++;
        step++;
    }
    if(str[i]=='.'){ //如有小数点继续读取
        i++;
        step++;
        double maf= 0.1;
        while( str[i]<=57 && str[i]>=48 ){
            double tmp=num.top();
            num.pop();
            num.push(tmp+(str[i]-'0')*maf);
            maf*=0.1;
            i++;
            step++;
        }
    }
    return step;
}


template<class T1, class T2>
T1 getans(string str, STACK<T1> &num, STACK<T2> &op){  //计算函数
    int t=str.length();
    op.push('#');
    int i=0;
    while(i<t ){
        if(isdigit(str[i])){
            i+=addunm(str,num,i);
        }
        else{
            switch (getOperation(op.top(), str[i])){
            case'<':{op.push(str[i]); break;}
            case'>':{
                    T1 tmp1 =num.top();num.pop();
                    T1 tmp2 =num.top();num.pop();
                    if(op.top() == '+' )
                        num.push(tmp2 + tmp1 );
                    if(op.top() == '-' )
                        num.push(tmp2 - tmp1 );
                    if(op.top() == '*' )
                        num.push(tmp2 * tmp1 );
                    if(op.top() == '/' )
                        num.push(tmp2 / tmp1 );
                    op.pop();
                 //   cout<<"加:"<<num.top()<<endl;
                    i--;break;
                    }
            case'=':{op.pop();break;}
            case' ': {cout<<"输入表达式有误"<<endl;exit(1);}
            }
            i++;
        }
    }
    return num.top();
}

应为定义的泛型,在getans函数中,返回值得类型和传人的数字栈的类型是一样的,所以就涉及到了int类型和float类型的不同,所以我把数字入栈单独出来(函数 addnum),循环读取,先读取整数位,在读取小数位,如果没有小数,小数位的读取会被忽略掉,读完后返回读取的位数(step),字符串str会往后跳step格,一直这样循环运算,直到表达式跑到尾,返回结果。


//方便伸手党给出完整的代码:

#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;

template<class T>
class STACK{
private:
    int p;
    int msize;
    T*  mdate;

public:
    STACK(){    //构造函数,申请栈空间
        p=-1;
        msize=50;
        mdate= (T*)malloc(sizeof(T)*50);
    }
    void push(T elem){  //插入元素
        if(p==msize-1){
            mdate=(T*)realloc(mdate, 20*sizeof(T) );
            msize += 20;
        }
        mdate[++p] =elem;
    }

    bool isempty(){  //判断栈是否为空
        return p==-1;
    }

    void pop(){    //删除元素
        if(isempty() )
            exit(1);
        --p;
    }

    T top(){  //返回栈顶元素
        return mdate[p];
    }

};

char getOperation(char c, char e){  //操作表
    char ope[7][7]={{'>','>','<','<','<','>','>'},
                    {'>','>','<','<','<','>','>'},
                    {'>','>','>','>','<','>','>'},
                    {'>','>','>','>','<','>','>'},
                    {'<','<','<','<','<','=',' '},
                    {'>','>','>','>',' ','>','>'},
                    {'<','<','<','<','<',' ','='}
                    };
    int i,j;
    if(c=='+') i=0;if(c=='-') i=1;if(c=='*') i=2;
    if(c=='/') i=3;if(c=='(') i=4;if(c==')') i=5;
    if(c=='#') i=6;
    if(e=='+') j=0;if(e=='-') j=1;if(e=='*') j=2;
    if(e=='/') j=3;if(e=='(') j=4;if(e==')') j=5;
    if(e=='#') j=6;
    return ope[i][j];
}

template<class T1>  //读取字符串中的数字
int addunm(string str, STACK<T1> &num, int i){
    int step=1;
    num.push(str[i++]-'0');
    while( str[i]<=57 && str[i]>=48 ){  //小数点前部分
        double tmp=num.top();
        num.pop();
        num.push(tmp *10 + (str[i]-'0'));
        i++;
        step++;
    }
    if(str[i]=='.'){ //如有小数点继续读取
        i++;
        step++;
        double maf= 0.1;
        while( str[i]<=57 && str[i]>=48 ){
            double tmp=num.top();
            num.pop();
            num.push(tmp+(str[i]-'0')*maf);
            maf*=0.1;
            i++;
            step++;
        }
    }
    return step;
}


template<class T1, class T2>
T1 getans(string str, STACK<T1> &num, STACK<T2> &op){  //计算函数
    int t=str.length();
    op.push('#');
    int i=0;
    while(i<t ){
        if(isdigit(str[i])){
            i+=addunm(str,num,i);
        }
        else{
            switch (getOperation(op.top(), str[i])){
            case'<':{op.push(str[i]); break;}
            case'>':{
                    T1 tmp1 =num.top();num.pop();
                    T1 tmp2 =num.top();num.pop();
                    if(op.top() == '+' )
                        num.push(tmp2 + tmp1 );
                    if(op.top() == '-' )
                        num.push(tmp2 - tmp1 );
                    if(op.top() == '*' )
                        num.push(tmp2 * tmp1 );
                    if(op.top() == '/' )
                        num.push(tmp2 / tmp1 );
                    op.pop();
                 //   cout<<"加:"<<num.top()<<endl;
                    i--;break;
                    }
            case'=':{op.pop();break;}
            case' ': {cout<<"输入表达式有误"<<endl;exit(1);}
            }
            i++;
        }
    }
    return num.top();
}

int main(){
    STACK<char> op ;  //复函栈
    STACK<double> num ;  //数字栈
    string Expression;  //表达式
    cout<<"输入表达式(以#结尾如:1+2+3+4#):";
    cin>>Expression;
    //此处ans的数据类型请和数据栈的数据类型保持一致
    //计算时会自动匹配
    double  ans=getans(Expression, num, op);
    cout<<ans <<endl;
    return 0;
}


欢迎大神指正,


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值