逆波兰式

在程序设计中,可能碰到需要对字符串数学表达式求值的问题,常用的方法是解析表达式,生成二叉树,然后进行计算。编译器就是使用这种方法来解析程序中的表达式的。这种方法实现起来有点难度,需要考虑运算符的优先级,括号的配对,堆栈的使用等等。我们正常情况下看到的数学表达式如果用二叉树遍历的话,恰好是中序遍历,故叫做中序表达式。除此之外,还有前序表达式,后序表达式。如:a+b+c(中序),++abc(前序),ab+c+(后序),如果表达式含有×,/,()等就更复杂了。

后缀表达式也称逆波兰表达式 因其使表达式求值变得轻松,所以被普遍使用。

没有括号的逆波兰式求解:

中缀表达式转换为逆波兰式:

将一个普通的中序表达式转换为逆波兰表达式的一般算法是(没有括号):

1、首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。

2、读入一个中缀表达式,为了方便起见,可在其最右端追加一个最低优先级运算符(如:#号)。(这样做的目的是,最后读入#号运算符时将运算符栈中所有运算符都输出)。

3、从左至右扫描该中缀表达式,如果当前字符是数字,则分析到该数字串的结束,并将该数字串直接输出。

4、如果不是数字,该字符则是运算符,此时需比较该运算符与运算符栈顶运算符的优先关系:

(1)、若该运算符优先级高于栈顶运算符优先级别(或栈为空),则直接将该运算符压入运算符栈中;

(2)、若该运算符优先级小于或等于此运算符栈顶的运算符,则弹出栈顶运算符并输出,重复比较、输出,直到栈为空或该运算符优先级高于栈顶运算符,然后将该运算符入栈。

5、重复上述操作(3)-(4)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,输出结果便是中缀表达式转化为逆波兰表示的简单算术表达式。

有括号的时候:

1.首先构造一个运算符栈,在这个栈中越往栈顶运算符的优先级越高。

2.构造一个数字栈,主要用来存放数字

3.读入一个中缀表达式,从左至右扫描表达式,如果字符是数字,则分析该数字串的结束,并将该字符串入数字栈

4.如果不是数字:

1.如果是左括号,直接入符号栈

2.如果是右括号,那么让符号栈中的符号依次出栈并依次进入数字栈直到遇到第一个右括号,并让该右括号出栈

3.如果是运算符,并且运算符的优先级高于栈顶元素,直接入符号栈

4.如果是运算符,并且优先级低于或者等于栈顶元素,那么运算符栈依次出栈并依次进入数字栈,直到运算符栈顶第一次出现比当前要入栈的运算符优先级低的符号,或者遇到第一个左括号,或者符号栈为空,那么当前符号入栈

5.如果是数字,直接入数字栈

6.最后数字栈中元素依次进入符号栈

最后符号栈中的元素依次出栈就是逆波兰式

项目代码github地址:https://github.com/ImTangYun/comprehensive/tree/master/C%2B%2B/algorithm/Reverse_Polish

    • Source Code
//
// 中序表达式(普通常见的运算表达式)转换成逆波兰式 本算法中包括了括号
//

#include <stdio.h>
#include <string>
#include <stack>
#include <unordered_map>

using std::unordered_map;
using std::stack;
using std::string;

string MtoReverse(const string &str)
{
    if (str.size() == 0) return "";
    unordered_map<char, int> pre;
    pre[‘+‘] = 0;
    pre[‘-‘] = 0;
    pre[‘*‘] = 1;
    pre[‘/‘] = 1;
    stack<char> s1;
    stack<char> s2;
    for (int i = 0; i < str.size(); ++i) {
        if (pre.find(str[i]) != pre.end()) {
            while (!s2.empty() && s2.top() != ‘(‘ && pre[str[i]] <= pre[s2.top()]) {
                s1.push(s2.top());
                s2.pop();
            }
            s2.push(str[i]);
        } else if (str[i] == ‘(‘){
            s2.push(str[i]);
        } else if (str[i] == ‘)‘) {
            while (s2.top() != ‘(‘) {
                s1.push(s2.top());
                s2.pop();
            }
            s2.pop();
        } else {
            s1.push(str[i]);
        }
    }
    while (!s1.empty()) {
        s2.push(s1.top());
        s1.pop();
    }
    string ret;
    while (!s2.empty()) {
        ret += s2.top();
        s2.pop();
    }
    return ret;
}

int main()
{
    string str = "a+b-c*x/(b+a)";
    printf("%s\n", MtoReverse(str).c_str());
    return 0;
}
时间: 2024-12-20 22:41:33

逆波兰式的相关文章

HDU1237 简单计算器 【栈】+【逆波兰式】

版本:1.0 日期:2014.5.17 2014.6.1 版权:© 2014 kince 转载注明出处 在介绍SwitchButton之前,先来看一下系统Button是如何实现的.源码如下: @RemoteView public class Button extends TextView { public Button(Context context) { this(context, null); } public Button(Context context, AttributeSet att

使用逆波兰式进行表达式求值

中缀表达式及后缀表达式图解中说明了使用逆波兰式进行表达式求值的方法,这里使用C++进行实现.实现和原理讲解有一点不同,需要进一步进行细化. 关于将中缀表达式转换成后后缀表达式的规则: 规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分:若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于找顶符号(乘除优先加减)则栈顶元素依次出找并输出,并将当前符号进栈,一直到最终输出后缀表达式为止. 上面的规则转换成下面的执行规则: 1.遇到操作数:直接输出(添加到后缀

逆波兰式与表达式求解

/*************** 逆波兰式即后缀表示法 预处理 ---- 中序表达式->逆序表达式(infix to postfix) 算法: while(表达式非空) if (遇到操作数) 直接输出 else if (遇到操作符op) op是( 直接入栈s op是) s.push输出,直到( op是四则运算,则 if (s为空 || s.top为( || op 优先级高于 s.top) op 入栈 else s.push输出 if (!s.empty) s.push输出 计算 算法: if (

python 逆波兰式

逆波兰式,也叫后缀表达式 技巧:为简化代码,引入一个不存在的运算符#,优先级最低.置于堆栈底部 class Stack(object): '''堆栈''' def __init__(self): self._stack = [] def pop(self): return self._stack.pop() def push(self, x): self._stack.append(x) 一.表达式无括号 def solve(bds): '''不带括号,引入#运算符''' pro = dict(

逆波兰式,有关栈的问题

/*有关逆波兰式的问题,也叫后缀表达式(将运算符写在操作数之后):例如:a+b的逆波兰式为a b +;下列程序是有关数字与数字相加的,将程序简单理解为,如果是数字,那么压入栈中,如果是运算符,那么出栈,将此前压入栈中的两个数取出栈并且相加,相加后再压入栈中,以此类推(按运算符的优先级!)*/ #include <stdio.h> #include <math.h>#include <stdlib.h>#include <ctype.h>#define STA

Haskell解决逆波兰式

摘自<Haskell趣学指南- Learn You a Haskell for Great Good> {- 逆波兰式(revese polish notation, RPN): 操作符出现在操作数的后面,而不是夹在它们中间. 如我们使用 "4 3 +" 而不是 "4 + 3". -} solveRPN :: String -> Double solveRPN = head . foldl foldingFunction [] . words wh

codechef Transform the Expression 转换成逆波兰式

把一般式子转换成逆波兰式. 这里的都是加括号的,难度降低点. Example Input: 3 (a+(b*c)) ((a+b)*(z+x)) ((a+t)*((b+(a+c))^(c+d))) Output: abc*+ ab+zx+* at+bac++cd+^* 知道其特点就好办: 1 遇到字母一定是可以输出的 2 遇到操作符号就入栈 3 遇到括号')',就出栈一个操作符 - 注意不是所有操作符出栈 不带括号的操作区别就在于是否需要判断符号的优先级. #include <stack> #i

将中缀式转化为逆波兰式 (栈)

逆波兰式:Reverse Polish notation,RPN,,也叫后缀表达式,将运算符写在操作数之后 数据结构:两个栈S1和S2.S1临时存储运算符,S2存储最终结果. 算法:(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符优先级大于S1栈栈顶运算符优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,则将该运算符送入

算法题---带加减乘除和括号的单字母变量表达式转化成逆波兰式

#include <stdio.h> #include <stdlib.h> #include <malloc.h> #define STACK_INIT_SIZE 100 #define STACK_INCREAMENT 10 #pragma warning(disable:4996)//我用的vs2015,不加这句用scanf会报错(使用了unsafe的函数) typedef struct { //栈 char *base; char *top; int stack