关于逆波兰表示法
逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。
逆波兰结构由弗里德里希·鲍尔(Friedrich L. Bauer)和艾兹格·迪科斯彻在1960年代早期提议用于表达式求值,以利用堆栈结构和减少计算机内存访问。逆波兰记法和相应的算法由澳大利亚哲学家、计算机学家查尔斯·汉布林(Charles Hamblin)在1960年代中期扩充。
举例:
中序表达式:
( 2 + ( ( 3 + 4 ) * ( 5 * 6 ) ) )
后序表达式:
2 3 4 + 5 6 * * +
规律:
- 中序和后序表达式中的数字顺序不变,都是2 3 4 5 6;
- 后序表达式中没有括号;
- 运算符的顺序与运算时的优先级相关;
分析:
- (3 + 4): 3 4 +;
- (5 * 6):5 6 * ;
- ( ( 3 + 4 ) * ( 5 * 6 ) ): 3 4 + 5 6 * *;
- ( 2 + ( ( 3 + 4 ) * ( 5 * 6 ) ) ): 2 3 4 + 5 6 * * +;
- 也就是:2 ((3 4 +)(5 6 *)*)+;
解题思路:
可以参考习题:1.3.9,需要用到双栈法的核心思想。
- 遇到数字直接打印,或顺序保存到字符串中;
- 遇到左括号“(”直接跳过;
- 遇到运算符就压入栈顶;
- 遇到“)”时,每当遇到一个“)”,就将弹出一个运算符,打印出来,或者接到字符串后面;
- 结果不涉及左右括号,所以不要费心思处理括号(太复杂),应该把右括号当做标志,作为操作栈的时机,这也是“双栈法”的精髓之一。
代码:
摘自《算法(第四版)》,我没做出来。
package chapter1_3;
import edu.princeton.cs.algs4.Stack;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
/**
* Compilation: javac InfixToPostfix.java
* Execution: java InfixToPostFix
* Dependencies: Stack.java StdIn.java StdOut.java
*
* Reads in an infix expression and outputs an equivalent postfix
* expression.
*
* Windows users: replace [Ctrl-d] with [Ctrl-z] to signify end of file.
*
* % java InfixToPostfix
* ( 2 + ( ( 3 + 4 ) * ( 5 * 6 ) ) )
* [Ctrl-d]
* 2 3 4 + 5 6 * * +
*
* % java InfixToPostfix | java EvaluatePostfix
* ( 2 + ( ( 3 + 4 ) * ( 5 * 6 ) ) )
* [Ctrl-d]
* 212
*/
public class InfixToPostfix {
public static void main(String[] args) {
Stack<String> stack = new Stack<String>();
while (!StdIn.isEmpty()) {
String s = StdIn.readString();
if (s.equals("+")) stack.push(s);
else if (s.equals("*")) stack.push(s);
else if (s.equals(")")) StdOut.print(stack.pop() + " ");
else if (s.equals("(")) StdOut.print("");
else StdOut.print(s + " ");
}
StdOut.println();
}
}
如何根据后序表达式运算:
public static void main(String[] args) {
Stack<Double> vals = new Stack<>();
while (!StdIn.isEmpty()) {
String s = StdIn.readString();
if (s.equals("+")) vals.push(vals.pop() + vals.pop());
else if (s.equals("-")) vals.push(vals.pop() - vals.pop());
else if (s.equals("*")) vals.push(vals.pop() * vals.pop());
else if (s.equals("/")) vals.push(vals.pop() / vals.pop());
else vals.push(Double.parseDouble(s));
}
StdOut.println("result = " + vals.pop());
}