【原创】基于逆波兰式法的数学表达式计算算法举例演示
2012-05-18 14:30
447 查看
基于逆波兰式法的数学表达式计算算法
基于逆波兰式法的数学表达式计算算法
我在上一篇文章中给出了计算规则,但没有举例,这里我举一个具体的例子做说明,方便大家理解。
上篇文章的地址:/article/5816101.html
里面有Delphi7版的源代码和按此方法开发的表达式计算器。
这里先给出运算符的优先级,表中0级优先级最低,7级最高,如下:
下面举一个简单的例子,计算表达式:2+(8+4^2)*3
主要分两步,第一步生成逆波兰表达式,第二步计算逆波兰表达式,如下:
第一、生成逆波兰表达式
首先构建一个存储器,另一个符号栈,存储器是从左向右储存数据,而符号栈则遵守后进先出的原则,计算表达式按从左至右的顺序扫描。
* 读入一个数据(重点注意:数值与函数名非单个字符,需要做判断处理)
1. 如果是左单目运算符或者函数名,直接入符号栈;比如 正负号 ~ @ max sin
2. 如果是右单目运算符,直接入存储器栈;比如 阶乘!与百分号%
3. 如果是运输量,则直接写入存储器;检查符号栈顶是否有单目运算符,有的话则全部出栈,并写入存储器;
4. 如果是左括号"(",则直接入符号栈;
5. 如果是右括号")",则弹出符号栈数据,写入存储器,一直到左括号弹出(左括弧直接丢弃,不写入存储器),再检查栈顶是否为左单目运算符或者函数名,是的话继续弹出,直到遇到双目运算符;
6. 如果是双目运算符,则与栈顶符号比较优先级,若大于栈顶优先级,则入栈;否则弹出栈顶符号并写入存储器,直到栈顶符号的运算优先级较小为止;
7.如果是函数参数的连接逗号“,”时,则弹出符号栈数据,直到遇到左括弧 ( 或者逗号,为止,再将逗号,入符号栈;
8.如果是结束符(表示表达式已全部读完),则符号栈全部弹出并写入存储器,否则继续按以上规则读取下一个数据;
下面将逐步介绍逆波兰式生成过程:
表达式按从左至右扫描,标记为红色的字符为当前步骤扫描的字符:
0、预处理:为表达式添加一个结束标示符“#”,扫描时按双目运算符考虑,
处理后表达式为:2+(8+4^2)*3#
1、2+(8+4^2)*3#:扫描“2”,按规则3,将运算量 2压入存储器,如下:
符号栈:暂空
2、2+(8+4^2)*3#:扫描“+”,按规则6,将加号压入符号栈,如下:
符号栈:
3、2+(8+4^2)*3#:扫描“(”,按规则4,将右括弧直接压入符号栈,如下:
符号栈:
4、2+(8+4^2)*3#:扫描“8”,按规则3,将运算量 8压入存储器,如下:
符号栈:
5、2+(8+4^2)*3#:扫描“+”,按规则6,优先级高于(,直接压入符号栈,如下:
符号栈:
6、2+(8+4^2)*3#:扫描“4”,按规则3,将运算量 4压入存储器,如下:
符号栈:
7、2+(8+4^2)*3#:扫描“^”,按规则6,优先级高于+, 直接压入符号栈,如下:
符号栈:
8、2+(8+4^2)*3#:扫描“2”,按规则3,将运算量2压入存储器,如下:
符号栈:
9、2+(8+4^2)*3#:扫描“)”,按规则5,依次弹出 ^ + 压入存储器,同时弹出符号栈左括弧,丢弃。如下:
符号栈:
10、2+(8+4^2)*3#:扫描“*”,按规则6,优先级高于+, 直接压入符号栈,如下:
符号栈:
11、2+(8+4^2)*3#:扫描“3”,按规则3,将运算量3压入存储器,如下:
符号栈:
12、2+(8+4^2)*3#:扫描“#”,按规则6,将符号栈优先级高的符号弹出压入存储器,,然后将#号压入符号栈,如下:
符号栈:
至此,表达式扫描结束,得到的存储器数值顺序就是逆波兰表达式。
第二、计算逆波兰表达式
按从左至右扫描数据存储器,扫描规则如下:
a、如果读出的是数据则压入计算中间值存储栈;
b、遇到单目运算符号就从计算中间值存储栈弹出一个数据进行运算,再把结果压回计算中间值存储栈;
c、遇到双目运算符号就从计算中间值存储栈弹出两个数据进行运算,再把结果压回计算中间值存储栈;这里需要注意减法与除法以及求幂等计算的顺序,第一次弹出的值作为减数和除数,第二次弹出的值作为被减数和被除数。
d、遇到逗号,就从计算中间值存储栈弹出两个数据用“,”连接起来直接将数值字符串压入计算中间值存储栈,不做计算。比如12 13,压入13,12
e、遇到函数,弹出计算中间值存储栈的相关数据调用函数进行计算;
具体计算步骤
这里除了前面的存储器外,还需要一个计算中间值存储栈。
然后从左至右扫描存储器,下面将给出计算步骤。
1、扫描“2”,按规则a,弹出后压入计算中间值存储栈,如下:
计算中间值存储栈:
2、依次扫描“8”,“4”,“2”,都遵循规则a,弹出后压入计算中间值存储栈,如下:
计算中间值存储栈:
3、扫描“^”,按规则c,弹出2、4,按求幂计算 4^2的结果16压入中间值存储栈,如下:
计算中间值存储栈:
4、扫描“+”,按规则c,弹出16、8,按求和计算结果24压入中间值存储栈,如下:
计算中间值存储栈:
5、扫描“3”,按规则a,弹出数值3后压入计算中间值存储栈,如下:
计算中间值存储栈:
6、扫描“*”,按规则c,弹出3、24,按相乘计算结果72压入中间值存储栈,如下:
计算中间值存储栈:
7、扫描“+”,按规则c,弹出72、2,按求和计算结果74压入中间值存储栈,如下:
计算中间值存储栈:
至此,存储器扫描完毕,也即计算完毕,
中间值存储栈中保存的74即为表达式的计算结果。
对于左右单目运算符的计算也是一样的,按上面的规则一样可以计算,对于函数的计算有些不一样,需要编写一些计算方法,具体大家可以看看我源代码里面的处理方法。
源代码下载地址:/article/5816101.html
基于逆波兰式法的数学表达式计算算法
我在上一篇文章中给出了计算规则,但没有举例,这里我举一个具体的例子做说明,方便大家理解。
上篇文章的地址:/article/5816101.html
里面有Delphi7版的源代码和按此方法开发的表达式计算器。
这里先给出运算符的优先级,表中0级优先级最低,7级最高,如下:
优先级 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
运算符 | # | ( | , | +- | * / | @ ~ | !% ^ | ) |
说明 | 表达式结束符 | 左括弧 | 函数参数连接符 | 加减 | 乘除 | 正负 | 阶乘,百分数,求幂 | 右括弧 |
主要分两步,第一步生成逆波兰表达式,第二步计算逆波兰表达式,如下:
第一、生成逆波兰表达式
首先构建一个存储器,另一个符号栈,存储器是从左向右储存数据,而符号栈则遵守后进先出的原则,计算表达式按从左至右的顺序扫描。
* 读入一个数据(重点注意:数值与函数名非单个字符,需要做判断处理)
1. 如果是左单目运算符或者函数名,直接入符号栈;比如 正负号 ~ @ max sin
2. 如果是右单目运算符,直接入存储器栈;比如 阶乘!与百分号%
3. 如果是运输量,则直接写入存储器;检查符号栈顶是否有单目运算符,有的话则全部出栈,并写入存储器;
4. 如果是左括号"(",则直接入符号栈;
5. 如果是右括号")",则弹出符号栈数据,写入存储器,一直到左括号弹出(左括弧直接丢弃,不写入存储器),再检查栈顶是否为左单目运算符或者函数名,是的话继续弹出,直到遇到双目运算符;
6. 如果是双目运算符,则与栈顶符号比较优先级,若大于栈顶优先级,则入栈;否则弹出栈顶符号并写入存储器,直到栈顶符号的运算优先级较小为止;
7.如果是函数参数的连接逗号“,”时,则弹出符号栈数据,直到遇到左括弧 ( 或者逗号,为止,再将逗号,入符号栈;
8.如果是结束符(表示表达式已全部读完),则符号栈全部弹出并写入存储器,否则继续按以上规则读取下一个数据;
下面将逐步介绍逆波兰式生成过程:
表达式按从左至右扫描,标记为红色的字符为当前步骤扫描的字符:
0、预处理:为表达式添加一个结束标示符“#”,扫描时按双目运算符考虑,
处理后表达式为:2+(8+4^2)*3#
1、2+(8+4^2)*3#:扫描“2”,按规则3,将运算量 2压入存储器,如下:
存储器: | 2 |
存储器: | 2 |
+ |
存储器: | 2 |
( |
+ |
存储器: | 2 | 8 |
( |
+ |
存储器: | 2 | 8 |
+ |
( |
+ |
存储器: | 2 | 8 | 4 |
+ |
( |
+ |
存储器: | 2 | 8 | 4 |
^ |
+ |
( |
+ |
存储器: | 2 | 8 | 4 | 2 |
^ |
+ |
( |
+ |
存储器: | 2 | 8 | 4 | 2 | ^ | + |
+ |
存储器: | 2 | 8 | 4 | 2 | ^ | + |
* |
+ |
存储器: | 2 | 8 | 4 | 2 | ^ | + | 3 |
* |
+ |
存储器: | 2 | 8 | 4 | 2 | ^ | + | 3 | * | + |
# |
第二、计算逆波兰表达式
按从左至右扫描数据存储器,扫描规则如下:
a、如果读出的是数据则压入计算中间值存储栈;
b、遇到单目运算符号就从计算中间值存储栈弹出一个数据进行运算,再把结果压回计算中间值存储栈;
c、遇到双目运算符号就从计算中间值存储栈弹出两个数据进行运算,再把结果压回计算中间值存储栈;这里需要注意减法与除法以及求幂等计算的顺序,第一次弹出的值作为减数和除数,第二次弹出的值作为被减数和被除数。
d、遇到逗号,就从计算中间值存储栈弹出两个数据用“,”连接起来直接将数值字符串压入计算中间值存储栈,不做计算。比如12 13,压入13,12
e、遇到函数,弹出计算中间值存储栈的相关数据调用函数进行计算;
具体计算步骤
这里除了前面的存储器外,还需要一个计算中间值存储栈。
然后从左至右扫描存储器,下面将给出计算步骤。
存储器: | 2 | 8 | 4 | 2 | ^ | + | 3 | * | + |
存储器: | 8 | 4 | 2 | ^ | + | 3 | * | + |
2 |
存储器: | ^ | + | 3 | * | + |
2 |
4 |
8 |
2 |
存储器: | + | 3 | * | + |
16 |
8 |
2 |
存储器: | 3 | * | + |
24 |
2 |
存储器: | * | + |
3 |
24 |
2 |
存储器: | + |
72 |
2 |
存储器: |
74 |
中间值存储栈中保存的74即为表达式的计算结果。
对于左右单目运算符的计算也是一样的,按上面的规则一样可以计算,对于函数的计算有些不一样,需要编写一些计算方法,具体大家可以看看我源代码里面的处理方法。
源代码下载地址:/article/5816101.html
相关文章推荐
- 【原创】Delphi实现数学表达式的计算(逆波兰式法)-四则运算解析
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用
- 面试算法:利用堆栈计算逆向波兰表达式
- 基于逆波兰表达式的公式解析器-算法和思路(一)
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用
- 算法基础系列之四:表达式计算及逆波兰栈
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用
- 基于逆波兰表达式的公式解析器-算法和思路(二)
- 面试算法:利用堆栈计算逆向波兰表达式
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用
- 算法--逆波兰表达式(数学逆波兰表达式和交并集逆波兰表达式)
- 从键盘上输入一个后缀表达式,试编写算法计算表达式的值。规定:逆波兰表达式的长度不超过一行,以$符作为输入结束,操作数之间用空格分隔,操作符只可能有+、-、*、/四种运算。例如:234 34+2*$。
- 我就给一个PHP逆波兰表达式的算法吧---工资计算专用