51nod3404 后缀表达式(逆波兰表达式)

本文介绍了后缀表达式(逆波兰表达式)的概念及其优点,提供了一个具体的计算后缀表达式的例子。在计算过程中,遇到数字时将其压入栈,遇到运算符时弹出栈顶两个数进行运算并把结果压回栈。文章还提到,可以使用递归方法解决后缀表达式的计算问题,时间复杂度为O(字符的个数)。

3404 后缀表达式(逆波兰表达式)

后缀表达式是一种把运算符后置的算术表达式,例如普通的表达式2 + 3的后缀表示法为2 3 +。后缀表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的后缀表示法为 2 3 + 4 *。本题求解后缀表达式的值,其中运算符包括+ - * /四个。

计算后缀表达式,要从前向后遍历字符串。当遇见运算数时,压入栈中。当读到运算符时,将栈中的连续2个运算数弹栈;用当前运算符计算后(注意后缀表达式的先出栈的运算数,放在运算符后面;后出栈的运算数,放在运算符前面),再将结果压栈。最后的栈顶就是后缀表达式的运算结果。

输入

输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数。

输出

输出为一行,表达式的值。
可使用以下语句保留固定长度的小数点后尾数
C++:cout<<setiosflags(ios::fixed)<<setprecision(6)<<ans<<endl;
C:printf("%.6lf\n", ans);

输入样例

11.0 12.0 + 24.0 35.0 + *

输出样例

1357.000000

样例解释

从前向后读入数据:
11.0: 11.0入栈        12.0: 12.0入栈        +: 将栈顶的 12.0 11.0 弹出,将运算结果23.0压入栈内(11.0+12.0=23.0)
24.0: 24.0入栈        35.0: 35.0入栈        +: 将栈顶的 35.0 24.0 弹出,将运算结果59.0压入栈内(24.0+35.0=59.0)
*: 将栈顶的 59.0 23.0 弹出,将运算结果1357.0压入栈内(23.0*59.0=1357.0)

解析:

波兰式符合递归结构,所以直接递归求解即可,时间复杂度O(字符的的个数)。

然后逆波兰表达式正好是波兰表达式逆过来得到式子,所以只需要先输入式子,然后从后往前递归即可,这里有两点需要注意,减的时候还要取反,除的时候要取倒数,因为递归求得是后面减前面,而正常的是前面减后面。

这里说明一下递归的过程,实际上波兰表达式是一颗二叉树,计算符号的儿子节点是数字,然后这两个数字通过父节点的计算符号计算出结果返回给上一层,最终返回给根节点得到波兰表达式的计算结果。

放代码:

#include<iostream>
#include<string>
#include<stack>
#include<cctype>
using namespace std;
string temp;
double x, a, b;
stack<double> s;
inline double cal(double a, char op, double b) {
    switch (op) {
    case '+': return a + b;
    case '-': return a - b;
    case '*': return a * b;
    case '/': return a / b;
    default : return 0;
    }
}
inline double trans(const string& s) {
    double k = 0.0, f = 1.0, frac = 1.0;
    bool flag = false;
    for(int i = 0; i < s.length(); ++i) {
        char c = s[i];
        if(c == '+') f = 1.0;
        else if(c == '-') f = -1.0;
        else if(c == '.') flag = true;
        else if(!flag) k = k * 10.0 + (c - 48);
        else frac /= 10.0, k += (c - 48) * frac;
    }
    return k * f;
}
int main() {
    while(cin >> temp) {
        if(isdigit(temp[0]) || isdigit(temp[1])) {
            x = trans(temp);
            s.push(x);
        }
        else {
            b = s.top(), s.pop();
            a = s.top(), s.pop();
            s.push(cal(a, temp[0], b));
        }
    }
    printf("%.6f", s.top());
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值