表达式求值

(表达式求值)

1.题目描述:

今天要破的题是四则运算表达式的求值,就是根据形如“(3/(2+1))-3*(4-5)”的字符串求解其表达式的值。学过数据结构的应该都会有印象栈的那一节讲过前缀、中缀、后缀表达式(逆波兰)可以用于求解表达式。话不多说,直接开始。

2.基本思路

基本思路就是根据已知的表达式字符串(中缀表达式),求得其对应的后缀表达式,然后根据后缀表达式直接计算得到表达式的值。(这里需要额外说明的是,中缀表达式对应着表达式的抽象语法树的中序遍历的结果,而后缀表达式则对应着后续遍历的结果,学过树的相关内容就会知道单纯从中序遍历的结果是无法唯一确定一颗二叉树的,至少需要中序+前序或中序+后序才能唯一确定一颗二叉树。但是这里由于每个运算符之间具有不同的优先级,因此可以根据中缀表达式求得唯一确定的后缀表达式)
这里分两部分进行介绍:
①中缀表达式转为后缀表达式:

step1: 声明符号栈S,从左到右扫描输入的字符串,得到当前字符c

step2: if c is digit:
       then c加入到后缀表达式的输出中

step3: if c is '(':
       then c S.push(c)

step4: if c is ')':
       逐一弹出S中的元素加入到后缀表达式的输出中,知道遇到'('为止,并将其丢弃

step5: while(c is 操作符)
           if 栈顶为空 或者 S.top为'(' 或者 c的优先级比S.top高
                S.push(c)
                break
           else
                弹出栈顶元素加入到后缀表达式的输出中

step6: 跳转到step1,直到字符串扫描结束为止

step7: 如果此时栈S仍不为空,则将栈内的元素逐一弹出,加入到后缀表达式的输出中

②后缀表达式求值

维护一个数字栈S
扫描得到的后缀表达式的字符串
    if(当前字符为数字)
        S.push(当前数字)
    else//当前字符为操作符(这里需要注意运算时操作数的顺序)
        根据操作符运算所需的操作数个数,弹出栈顶元素进行运算
        并将运算的结果压入到栈中

字符串识别结束后,栈内只有一个元素,即运算的结果。

3.代码实现

#include <iostream>
#include <string>
#include <stack>
#include <map>
using namespace std;


stack<char> Op;

map<int,int> prior;

bool isOp(char c){
    if(c=='-'||c=='+'||c=='*'||c=='/'||c=='^'||c=='!')
        return true;
    else
        return false;
}

int jiechen(int n){
    int x=1;
    for(int i=1;i<=n;i++){
        x*=i;
    }
    return x;
}

int power(int x,int n){
    int ans=1;
    for(int i=1;i<=n;i++){
        ans*=x;
    }
    return ans;
}

int main()
{

    prior['+'] = 1,prior['-'] = 1,prior['*'] = 2,prior['/'] = 2,prior['^'] = 3,prior['!']=4;

    string src="",tar="";//src为中缀表达式,tar为后缀表达式

    cin>>src;
    int len = src.size();

    //中缀表达式转为后缀表达式
    for(int i=0;i<len;i++){//扫描输入的字符串
        if(src[i]<='9'&&src[i]>='0')//当输入为操作数时
            tar += src[i];
        else if(src[i]=='(')//当输入为左括号时
            Op.push(src[i]);
        else if(src[i]==')'){//当输入为右括号时
            while(Op.top()!='('){
                    tar+=Op.top();
                    Op.pop();
            }
            Op.pop();
        }
        while(isOp(src[i])){//当输入为操作符时
            if(Op.size()==0||Op.top()=='('||prior[Op.top()]<prior[src[i]]){
                Op.push(src[i]);
                break;
            }
            else{
                tar+=Op.top();
                Op.pop();
            }
        }
    }
    while(Op.size()!=0){//当输入结束时,如果栈内还有元素的话
        tar+=Op.top();
        Op.pop();
    }
    cout<<tar<<endl;

    //后缀表达式求值
    int lentar = tar.size();

    stack<int> Num;
    for(int i=0;i<lentar;i++){
        if(tar[i]<='9'&&tar[i]>='0'){
            Num.push(tar[i]-'0');
        }
        else{
            int num1,num2;
            if(tar[i]=='+'){
                num1=Num.top(),Num.pop();
                num2=Num.top(),Num.pop();
                Num.push(num1+num2);
            }
            else if(tar[i]=='-'){//注意操作数的运算顺序
                num1=Num.top(),Num.pop();
                num2=Num.top(),Num.pop();
                Num.push(num2-num1);
            }
            else if(tar[i]=='*'){
                num1=Num.top(),Num.pop();
                num2=Num.top(),Num.pop();
                Num.push(num1*num2);
            }
            else if(tar[i]=='/'){//注意操作数的运算顺序
                num1=Num.top(),Num.pop();
                num2=Num.top(),Num.pop();
                Num.push(num2/num1);
            }
            else if(tar[i]=='^'){//注意操作数的运算顺序
                num1=Num.top(),Num.pop();
                num2=Num.top(),Num.pop();
                Num.push(power(num2,num1));
            }
            else if(tar[i]=='!'){//注意操作数的运算顺序
                num1=Num.top(),Num.pop();
                Num.push(jiechen(num1));
            }
        }
    }
    cout<<Num.size()<<endl;
    cout<<"The result is:"<<Num.top()<<endl;

    return 0;
}
/*
(3^2/(2+1))-3*(4-5)+2!
1+2!-3*(4-5)
1+2*(3-4)-5*6
*/
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值