【讲古堂】表达式求值

【讲古堂】表达式求值

dubenju@126.com 2015/12/27)算法

 

什么是表达式

表达式是由数字,操做符,变量,常量等有意义地组合而成并能求得结果的式子。spa

例如:对象

32 + ( ( 9 * Celsius ) / 5 )递归

4 + 2 * 55 / 2.5token

组成表达式的信息种类繁多,这里只讨论数字表达式,即表达式由如下要素构成:get

数字、操做符、变量、常量。数学

 

数字

不考虑进制的话,一般指十进制数,小数的时候是有小数点的。数字一般是以被操做对象的身分出如今表达式中的,叫作操做数。it

 

操做符

表示对操做数进行哪一种操做的符号叫作操做符,被操做的值叫作操做数,对操做数进行操做的过程称为表达式求值。根据操做对象的个数分为一元操做符和二元操做符。变量

一元操做符,操做只应用于单一操做数。例如:23!-n。二叉树

操做应用于两个操做数的叫二元操做符。例如:6*2一、29/十一、6.9+19.八、21.1-2.8

优先级

相对其余操做符,每一个操做符都有一个优先级,优先级高的操做符比优先级低的操做符优先应用。通常的优先级是这样设置的:

分组操做符()具备最高优先级。

一元操做符-+比乘除模的优先级高。

次方乘除模比加减法的高。

操做数的类型变换

类型变换是指操做的过程当中操做数的类型发生变化的现象。

好比:

1/3

1.5/0.3

 

变量与常量

变量是指值能够变化的量。好比x+5中的x。

常量是指通常不发生变化并表明某一数值的量。好比:pi=3.1415926。

 

表达式的递归

这里所谓的递归是指一个表达式的结果能够做为另外一表达式的操做数。

例如:

1 + 2 * 3

        2 * 3

1 + 6

 

表达式的表示方法

中缀表示

1 + x * 3 + 4 / x

操做符是以中缀形式处于操做数的中间(例:3 + 4)。中缀表达式不容易被计算机解析,但由于它符合人们的广泛用法,被许多程序语言使用。至关于语法树的中序遍历获得的结果。

 

前缀表示(波兰式)

+ + 1 * x 3 / 4 x

操做符置于操做数的前面。若是操做符的元数(arity)是固定的,则语法上不须要括号仍然能被无歧义地解析。波兰式是波兰数学家扬·武卡谢维奇1920年代引入的,用于简化命题逻辑。至关于语法树的前序遍历获得的结果。

 

后缀表示(逆波兰式)

1 x 3 * + 4 x / +

操做符置于操做数的后面。逆波兰记法不须要括号来标识操做符的优先级。易于程序实现。至关于语法树的后序遍历获得的结果。

 

表达式的分解parse

把表达式分解成不可再细分的基本元素的过程。

记号(token)的类型

变量variable

数值number

操做符operator

 

字符0-9和小数点.的话则是数值型。

是预先登记的变量的话则是变量型(常量等同于变量)。

如果操做符的话则是操做符型。

上述之外的话则是不正确的类型。

 

表达式的分析

语法检查

语法错误就是表达式没有遵循分析程序的严格规则。多数状况下,语法错误都是人为错误,好比输入失误等,如下表达式是非法的10**8(10-5)*9)/8

 

表达式求值

基于中缀表示的表达式求值

分别针对操做数和操做符构建表达式,必要时采用递归的方式。因为实现起来比较复杂,多不采用,故不做细述。

 

基于前缀表示的表达式求值

对于解析后的记号,从后向前进行,若是扫描到操做数,则压进栈,若是扫描到操做符,则根据操做符的操做数个数从栈中弹出相应个数的操做数来进行相应的操做,并将结果压进栈,当扫描结束后,栈的栈顶就是表达式结果。

 

基于逆波兰表示的表达式求值

针对逆波兰,能够用一个栈来实现计算,扫描从左往右进行,若是扫描到操做数,则压进栈,若是扫描到操做符,则根据操做符的操做数个数从栈中弹出相应个数的操做数来进行相应的操做,并将结果压进栈,当扫描结束后,栈的栈顶就是表达式结果。

 

调度场算法

中缀表达式转换成后缀表达式

  既然中缀表达式对于计算机的运算并不便利,而前缀后缀表达式的计算相对简单方便。所以,找到一种途径将中缀表达式转换成前缀后缀表达式就十分重要。实际上,两者的转换算法看起来也很像一个逆过程。所以,咱们着重讨论中缀转后缀。

从理论上讲,已知一棵二叉树的中序遍历序列,要求出它的后序遍历序列是不惟一的,即文法是有多义性的。可是,在这里加上了优先级这一限制条件,转换就变得惟一了。

所谓的调度场算法是操做数直接输出,操做符的话要和栈内的操做符进行比较,优先级高的出栈输出,而后当前操做符入栈。在最后,把栈内剩余的所有输出。这里的栈起到了调度场的做用。

 

中缀表达式转换成前缀表达式

  中缀表达式转换成前缀表达式和中缀表达式转换成后缀表达式十分相似,只须要将扫描方向由前日后变成由后往前,将'('改成')',')'改成'(',注意其中一个判断优先级的地方须要由>=变成>便可。

相关文章
相关标签/搜索