标签:
最近在学习stanford的Swift课程,里面开发了一个计算器,需要添加中缀转后缀的算法。所以在这复习下中算法思想。
一个多项式一般可以写成中缀表达式和后缀表达式来(前缀用的不多),中缀实际上就是人们正常语境中的逻辑方式,举两个例子:
a1. 1+2*3+(4+5)*6
b1. ((1+2)*3+4)*5+6
中缀表达式机器不好理解,而后缀表达式相对来说对机器比较友好,后缀表达式又称逆波兰式 ,定义如下
(1)如果E是一个变量或
常量,则E的
后缀式是E本身。
(2)如果E是E1 op E2形式的表达式,这里op是如何二元操作符,则E的后缀式为E1‘E2‘ op,这里E1‘和E2‘分别为E1和E2的后缀式。
(3)如果E是(E1)形式的表达式,则E1的后缀式就是E的后缀式。
如:我们平时写a+b,这是中缀表达式,写成
后缀表达式就是:ab+
(a+b)*c-(a+b)/e的后缀表达式为:
(a+b)*c-(a+b)/e
→((a+b)*c)((a+b)/e)-
→((a+b)c*)((a+b)e/)-
→(ab+c*)(ab+e/)-
→ab+c*ab+e/-
上面的一堆的就是如何从形式上把一个中缀变成后缀,用在a1上就是
a1. 1+2*3+(4+5)*6
a1*. (1+(2*3))+((4+5)*6)
->(1+(2,3,*))+((4,5,+)*6)
->(1,(2,3,*),+) + ((4,5,+),6,*)
->(1,2,3,*,+) + (4,5,+,6,*)
->(1,2,3,*,+) ,(4,5,+,6,*),+
->1,2,3,*,+,4,5,+,6,*,+
程序上如何实现呢? 一种简单的方式是用栈(用树的遍历也行,就是创建树麻烦点)
一般用两个临时栈,
S1用来放操作符,加减乘除,括号等等的。在栈底先放个#操作符代表最低优先级算符。
S2用来放输出的后缀式,操作数也是直接压入这里。
假设只包含加减乘除和括号,算法规则如下:
从左到右依次读取中缀表达式 ,比如“1+2*3+(4+5)*6”,先弹出“1”,最后到“6”
1.读到操作数,直接压入S2栈顶。
2.读到非括号操作符 则按照有限级操作
如果操作符比S1栈顶操作符优先级高,则直接压入栈顶。(这里可以解释为什么要放个#在栈底,因为第一个操作符可以和#比较,程序比较归一化)
如果操作符比S1栈顶操作符优先级不高,则弹出S1栈顶并压入S2,直到当前操作符高于S1栈顶,然后将当前操作符压入S1栈顶。
3.读到(,直接压入S1栈顶。
4.读到),则弹出离S1栈顶最近的(到栈顶间的所有操作符压入S2,之后弹出该(。
5.当中缀表达式读取完毕,将S1内剩余的操作符逐个弹出并压入S2
6.S2中即为后缀表达式(从底到顶,如果S2出栈得反转下)
a1. 1+2*3+(4+5)*6
S1.#,
S2.
S1.#,+,(,+
S2.1,2,3,*,+,4,5
S1.#,+,
S2.1,2,3,*,+,4,5,+
S1.#,+,*
S2.1,2,3,*,+,4,5,+6
S1.#
S2.1,2,3,*,+,4,5,+,6,*,+ (end)
b1. ((1+2)*3+4)*5+6
S1.#,*
S2.1,2,+,3,*,4,+,5,
S1.#,+
S2.1,2,+,3,*,4,+,5,*,6
S1.#
S2.1,2,+,3,*,4,+,5,*,6,+ (end)
逆波兰算法
标签:
原文地址:http://www.cnblogs.com/uncleqiang/p/4892739.html