【原创】基于逆波兰式法的数学表达式计算算法举例演示

基于逆波兰式法的数学表达式计算算法

基于逆波兰式法的数学表达式计算算法

我在上一篇文章中给出了计算规则,但没有举例,这里我举一个具体的例子做说明,方便大家理解。

上篇文章的地址:http://www.cnblogs.com/tangqs/archive/2011/11/03/2234715.html

里面有Delphi7版的源代码和按此方法开发的表达式计算器。

这里先给出运算符的优先级,表中0级优先级最低,7级最高,如下:

优先级

0

1

2

3

4

5

6

7

运算符

#

*  /

@  ~

% ^

)

说明

表达式结束符

左括弧

函数参数连接符

加减

乘除

正负

阶乘,百分数,求幂

右括弧

 

下面举一个简单的例子,计算表达式:2+8+4^2*3

主要分两步,第一步生成逆波兰表达式,第二步计算逆波兰表达式,如下:

第一、生成逆波兰表达式

首先构建一个存储器,另一个符号栈存储器是从左向右储存数据,而符号栈则遵守后进先出的原则,计算表达式按从左至右的顺序扫描。

* 读入一个数据(重点注意:数值与函数名非单个字符,需要做判断处理)

1. 如果是左单目运算符或者函数名,直接入符号栈;比如 正负号 ~ @ max sin

2. 如果是右单目运算符,直接入存储器栈;比如 阶乘!与百分号%

3. 如果是运输量,则直接写入存储器;检查符号栈顶是否有单目运算符,有的话则全部出栈,并写入存储器;

4. 如果是左括号"(",则直接入符号栈;

5. 如果是右括号")",则弹出符号栈数据,写入存储器,一直到左括号弹出(左括弧直接丢弃,不写入存储器),再检查栈顶是否为左单目运算符或者函数名,是的话继续弹出,直到遇到双目运算符;

6. 如果是双目运算符,则与栈顶符号比较优先级,若大于栈顶优先级,则入栈;否则弹出栈顶符号并写入存储器,直到栈顶符号的运算优先级较小为止;

7.如果是函数参数的连接逗号“,”时,则弹出符号栈数据,直到遇到左括弧 ( 或者逗号,为止,再将逗号,入符号栈;

8.如果是结束符(表示表达式已全部读完),则符号栈全部弹出并写入存储器,否则继续按以上规则读取下一个数据;

 

下面将逐步介绍逆波兰式生成过程:

表达式按从左至右扫描,标记为红色的字符为当前步骤扫描的字符:

0、预处理:为表达式添加一个结束标示符#”,扫描时按双目运算符考虑,

处理后表达式为:2+8+4^2*3#

12+8+4^2*3#扫描“2,按规则3,将运算量 2压入存储器,如下:

存储器:

2

 

 

 

 

 

 

 

 

 

 

 

 

符号栈:暂空

 

22+8+4^2*3#扫描“+”,按规则6,将加号压入符号栈,如下:

存储器:

2

 

 

 

 

 

 

 

 

 

 

 

 

符号栈:

+

32+8+4^2*3#扫描“”,按规则4,将右括弧直接压入符号栈,如下:

存储器:

2

 

 

 

 

 

 

 

 

 

 

 

 

符号栈:

+

42+8+4^2*3#扫描“8,按规则3,将运算量 8压入存储器,如下:

存储器:

2

8

 

 

 

 

 

 

 

 

 

 

 

符号栈:

+

52+8+4^2*3#扫描“+”,按规则6,优先级高于(,直接压入符号栈,如下:

存储器:

2

8

 

 

 

 

 

 

 

 

 

 

 

符号栈:

+

+

62+8+4^2*3#扫描“4,按规则3,将运算量 4压入存储器,如下:

存储器:

2

8

4

 

 

 

 

 

 

 

 

 

 

符号栈:

+

+

72+8+4^2*3#扫描“^”,按规则6,优先级高于+, 直接压入符号栈,如下:

存储器:

2

8

4

 

 

 

 

 

 

 

 

 

 

符号栈:

^

+

+

82+8+4^2*3#扫描“2,按规则3,将运算量2压入存储器,如下:

存储器:

2

8

4

2

 

 

 

 

 

 

 

 

 

符号栈:

^

+

+

92+8+4^2*3#扫描“)”,按规则5,依次弹出 ^  + 压入存储器,同时弹出符号栈左括弧,丢弃。如下:

存储器:

2

8

4

2

^

+

 

 

 

 

 

 

 

符号栈:

+

102+8+4^2*3#扫描“*”,按规则6,优先级高于+, 直接压入符号栈,如下:

存储器:

2

8

4

2

^

+

 

 

 

 

 

 

 

符号栈:

*

+

112+8+4^2*3#扫描“3,按规则3,将运算量3压入存储器,如下:

存储器:

2

8

4

2

^

+

3

 

 

 

 

 

 

符号栈:

*

+

122+8+4^2*3#扫描“#”,按规则6,将符号栈优先级高的符号弹出压入存储器,,然后将#号压入符号栈,如下:

存储器:

2

8

4

2

^

+

3

*

+

 

 

 

 

符号栈:

#

至此,表达式扫描结束,得到的存储器数值顺序就是逆波兰表达式


第二、计算逆波兰表达式

按从左至右扫描数据存储器扫描规则如下:

a、如果读出的是数据则压入计算中间值存储栈

b、遇到单目运算符号就从计算中间值存储栈弹出一个数据进行运算,再把结果压回计算中间值存储栈

c、遇到双目运算符号就从计算中间值存储栈弹出两个数据进行运算,再把结果压回计算中间值存储栈;这里需要注意减法与除法以及求幂等计算的顺序,第一次弹出的值作为减数和除数,第二次弹出的值作为被减数和被除数。

d、遇到逗号,就从计算中间值存储栈弹出两个数据用连接起来直接将数值字符串压入计算中间值存储栈,不做计算。比如 12 13 ,压入13,12

e、遇到函数,弹出计算中间值存储栈的相关数据调用函数进行计算;

 

具体计算步骤

这里除了前面的存储器外,还需要一个计算中间值存储栈

然后从左至右扫描存储器,下面将给出计算步骤。

存储器:

2

8

4

2

^

+

3

*

+

 

 

1扫描“2,按规则a,弹出后压入计算中间值存储栈,如下:

存储器:

 

8

4

2

^

+

3

*

+

 

 

计算中间值存储栈

2

2、依次扫描“8,“4,“2,都遵循规则a,弹出后压入计算中间值存储栈,如下:

存储器:

 

 

 

 

^

+

3

*

+

 

 

计算中间值存储栈

2

4

8

2

3扫描“^”,按规则c,弹出24,按求幂计算 4^2的结果16压入中间值存储栈,如下:

存储器:

 

 

 

 

 

+

3

*

+

 

 

计算中间值存储栈

16

8

2

4扫描“+”,按规则c,弹出168,按求和计算结果24压入中间值存储栈,如下:

存储器:

 

 

 

 

 

 

3

*

+

 

 

计算中间值存储栈

24

2

5扫描“3,按规则a,弹出数值3后压入计算中间值存储栈,如下:

存储器:

 

 

 

 

 

 

 

*

+

 

 

计算中间值存储栈

3

24

2

6扫描“*”,按规则c,弹出324,按相乘计算结果72压入中间值存储栈,如下:

存储器:

 

 

 

 

 

 

 

 

+

 

 

计算中间值存储栈

72

2

7扫描“+”,按规则c,弹出722,按求和计算结果74压入中间值存储栈,如下:

存储器:

 

 

 

 

 

 

 

 

 

 

 

计算中间值存储栈

74

至此,存储器扫描完毕,也即计算完毕,

中间值存储栈中保存的74即为表达式的计算结果

 

对于左右单目运算符的计算也是一样的,按上面的规则一样可以计算,对于函数的计算有些不一样,需要编写一些计算方法,具体大家可以看看我源代码里面的处理方法。

 

源代码下载地址:http://www.cnblogs.com/tangqs/archive/2011/11/03/2234715.html

 

posted on 2012-05-18 14:30  唐朝t  阅读(2827)  评论(0编辑  收藏  举报