RPN/逆波兰式
逆波兰式(Reverse Polish notation,RPN,或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后)
https://github.com/KafuuNeko/CRPN
一.将一个普通的中缀表达式转换为逆波兰表达式
首先定义一个存储运算符的栈S,以及一个存放结果的字符串R
a.接着遍历普通中缀表达式的每个字符,定义当前玻璃到的字符名称为C
若C是数字,则直接加入结果R
若C为运算符,则判断该运算符类型
1.若为右括号’)’,则不断弹出栈S中的符号输出至结果,直至遇到左括号
2.若为左括号'(‘,则直接将此运算符加入到栈S
3.若为数学运算符(+, -, , /, %)则判断运算符优先级
最低优先级:左括号'(‘
第二优先级:+ -
第一优先级: / %
接着获取栈S顶栈运算符的优先级,若顶栈运算符优先级大于或等于C运算符优先级,则弹出栈S顶栈运算符,加入至结果R,并重复此步骤,直至栈S顶栈运算符的优先级小于C运算符的优先级或栈S为空,接着将C运算符入栈S
b.处理完表达式字符串后,如果栈S内还有残留数据,那么依次出栈,加入到结果R
ExampleA:20 + 10 * 8
1[C:20]:数字直接加入结果
R=[20], S=[]
2[C:+] :运算符+,则判断栈S顶栈运算符的优先级,因为此时栈S为空,所以直接加入到栈S
运算符R=[20], S=[+]
3[C:10]:数字直接加入结果
R=[20, 10], S=[+]
4[C:] :运算符,当前栈S顶栈运算符为+,优先级低于*,所以C直接加入到栈S
R=[20, 10], S=[+, *]
5[C:8] :数字直接加入结果
R=[20, 10, 8], S=[+, *]
处理完成,但此时栈不为空,则依次弹出栈内元素至结果
最终结果R=[20, 10, 8, *, +] 20 10 8 * +
ExampleB:10 + 5 * (20 - 5 - 10) + 8 - 10 / 2
1[C:10] :数字直接加入结果
R=[10], S=[]
2[C:+] :运算符+,则判断栈S顶栈运算符的优先级,因为此时栈S为空,所以直接加入到栈S
运算符R=[10], S=[+]
3[C:5] :数字直接加入结果
R=[10, 5], S=[+]
4[C:] :运算符,当前栈S顶栈运算符为+,优先级低于*,所以C直接加入到栈S
R=[10, 5], S=[+, *]
5[C:(] :左括号,直接将此运算符加入到栈S
R=[10, 5], S=[+, *, (]
6[C:20] :数字直接加入结果
R=[10, 5, 20], S=[+, *, (]
7[C:-] :运算符-,栈S顶栈为左括号'(',因为左括号优先级小于-,所以C直接加入栈S
R=[10, 5, 20], S=[+, *, (, -]
8[C:5] :数字直接加入结果
R=[10, 5, 20, 5], S=[+, *, (, -]
9[C:-] :运算符-,栈S顶栈运算符与C运算符优先级相同,弹出栈S顶栈内容至R后栈S顶栈为左括号'(',优先级小于运算符C,所以C再此时入栈S
R=[10, 5, 20, 5, -], S=[+, *, (, -]
10[C:10]:数字直接加入结果
R=[10, 5, 20, 5, -, 10], S=[+, *, (, -]
11[C:)] :右括号')',不断弹出栈S中的符号输出至结果,直至遇到左括号
R=[10, 5, 20, 5, -, 10, -], S=[+, *]
12[C:+] :运算符+,弹出栈S内所有优先级大于或等于运算符+的符号至结果R后将C入栈
R=[10, 5, 20, 5, -, 10, -, *, +], S=[+]
13[C:8] :数字直接加入结果
R=[10, 5, 20, 5, -, 10, -, *, +, 8], S=[+]
14[C:-] :运算符-,弹出栈S内所有优先级大于或等于运算符+的符号至结果R后将C入栈
R=[10, 5, 20, 5, -, 10, -, *, +, 8, +], S=[-]
15[C:10] :数字直接加入结果
R=[10, 5, 20, 5, -, 10, -, *, +, 8, +, 10], S=[-]
16[C:/] :运算符/,此时栈S顶栈运算符‘-’的优先级小于‘/’,所以C直接加入栈S
R=[10, 5, 20, 5, -, 10, -, *, +, 8, +, 10], S=[-, /]
17[C:2] :数字直接加入结果
R=[10, 5, 20, 5, -, 10, -, *, +, 8, +, 10, 2], S=[-, /]
处理完成,但此时栈不为空,则依次弹出栈内元素至结果
R=[10, 5, 20, 5, -, 10, -, *, +, 8, +, 10, 2, /, -]
最终结果:10 5 20 5 - 10 - * + 8 + 10 2 / -
二.计算逆波兰表达式
计算方式十分简单,我们先定义一个存放数字的栈S
接着遍历逆波兰表达式,遇到数字则加入数字栈,遇到运算符则弹出两个数字栈顶栈数字,并使用此运算符对这两个数字进行计算,并将计算结果加入到数字栈内
ExampleA:20 10 8 * +
1[C:20] :C加入到栈S
S=[20]
2[C:10] :C加入到栈S
S=[20, 10]
3[C:8] :C加入到栈S
S=[20, 10, 8]
4[C:*] :取出栈S顶栈两个元素 N1:8, N2:10
使用此运算符计算结果:R:N1 * N2 = 80,并将结果重新入栈
S=[20, 80]
5[C:+] :取出栈S顶栈两个元素 N1:20, N2:80
使用此运算符计算结果:R:N1 + N2 = 100,并将结果重新入栈
S=[100]
当完成这些步骤后,栈S内剩下的最后一个元素即为表达式的计算结果,如果最后栈内元素不唯一,或在遍历到运算符时栈内元素数量少于2个,则都判定为此表达式有误
