逆波兰表达式

来源:互联网 发布:mindmap中文版软件 编辑:程序博客网 时间:2024/05/21 17:24

逆波兰表达式又叫做后缀表达式。在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,这种表示法也称为中缀表示。波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法,按此方法,每一运算符都置于其运算对象之后,故称为后缀表示。


逆波兰表达式在编译技术中有着普遍的应用。
运算符优先级:从小到大排序,相同优先级没有用逗号隔开:(,+-,*\,负号,)
运算符优先级:

( ) 1

+- 2

*/ % 3

值越大优先级越高,注意括号优先级是最低的。

表达式:2*(1+2/2)

定义集合E储存分离的表达式,E{ 2, *, (, 1, +, 2, /, 2, ) }

定义集合R储存逆波兰, R{…}

定义堆栈S储存运算符, S{…}

从左到右遍历E,开始判断

E[0]是数字2,直接添加到R,R{ 2 }

E[1]是乘号,和栈内运算符比较优先级,这时栈为空,所有直接入栈,S{*}

E[2]是左括号,直接入栈,S{ *, ( }

E[3]是数字1,直接添加到R,R{ 2, 1 }

E[4]是加号,比较栈顶运算符,栈顶为”(“,加号比它优先级高,所有直接入栈, S{ *, (, + }

E[5]是数字2,直接添加到R, R{ 2, 1 , 2 }

E[6]是除号,比较栈顶运算符,栈顶为”+”,除号>加号,直接入栈, S{ *, (, +, / }

E[7]是数字2,直接添加到R,R{2, 1, 2, 2}

E[8]是右括号,把栈内运算符出栈并添加到R直到遇到第一个左括号,R{ 2, 1, 2, 2, /, + } S{ * },注意左括号出栈但不加到R

那么整个过程就完毕,最后一步把栈内的所有元素添加到R

R{ 2, 1, 2, 2, /, +, * } S{…}

那么表达式2*(1+2/2) 转逆波兰变成 2 1 2 2 / + *

计算逆波兰非常简单,也需要一个堆栈,规则是:

1.从左到右遍历R

2.如果该元素是数字,直接入栈

3.如果该元素是运算符,出栈两个数,计算结果再入栈,逆波兰遍历完后栈内的元素就是表达式的值了

如:R{ 2, 1, 2, 2, /, +, * }

1.数字就入栈,那么S{ 2, 1, 2, 2 }

2.除号,出栈两个2 / 2 = 1,再入栈 S{ 2, 1, 1 }

3.加号,出栈两个1 + 1 = 2,再入栈S{ 2, 2 }

4.乘号,出栈两个2 * 2 = 4,再入栈S{ 4 }

5.逆波兰已遍历完,栈内元素是4,对照下普通表达式的运算结果是否相同?

关于预处理问题

转换成逆波兰前必须先要处理一下

A.比如你要分离普通表达式的时候,负号和减号是相同的,得把减号用其他符号代替,怎么判断是减号还是负号?很简单,从右往左遍历,遇到”-“时再判断它的前一个符,如果是数字或者右括号,那么它就是减号!

B.如果表达式的第一个符是负号,也就是形如-(1+2),那么根据上面第一条的判断它为负号而不是减号,分离这个表达式时就会变成 - ( 1 + 2 ),负号就会被独立分离出来,这样转逆波兰是没有问题,但是计算逆波兰就有问题,它会被转成逆波兰为:- 1 2 +的样子,因为负号会被认为是运算符,所以把栈内元素出栈计算,这时栈根本就是为空的,就会出异常!解决办法是如果表达式的第一个符号为负号,在整个表达式前面加一个0,就会变成

0-(1+2),这样根据A判断”-“就会被当成是减号而不是负号,0减去后面的数不就是负数了嘛!

C.类似第2条,看下形如1*-(-(-(1+2)))这样的表达式,根据A的判断”-“会被当成负号,显然,和B一样,也会出现一样的错误,解决办法还是加0,首先判断如果它是负号,再判断它后面是数字还是运算符,如果是运算符就在负号前面加个0,那么整个下来表达式就会变成1*0-(0-(0-(1+2)))

0 0
原创粉丝点击