前序表达式 , 中序表达式 , 后序表达式
- 中序表达式
中序表达式即我们日常使用的表达式,从左往右阅读,结构清晰,但是需要括号改变优先级,对计算机不友好
eg:(1+4)*3+10/5,2*3/(2-1)+3*(4-1) - 前序表达式(波兰表示法Polish notation,或波兰记法)
前序表达式的特点是操作符置于操作数前面,如果操作符的元数(+是二元操作符,故元数是2),则语法上不需要括号仍然能被无歧义的解释,不需要括号改变优先级。
eg:
中序表达式: (1+4)*3+10/5
前序表达式: + * + 1 4 3 / 10 5
前序表达式的计算:
eg:
+ * + 1 4 3 / 10 5
step1: 10 / 5 => 2
new expression: + * + 1 4 3 2
step2: 1 + 4 => 5
new expression: + * 5 3 2
step3: 5 * 3 => 15
new expression: + 15 2
step4: 15 + 2 => 17
前序表达式的求值:
首先要从右至左扫描表达式,从右边第一个字符开始判断,如果当前字符是数字则继续扫描,如果当前字符是运算符,将运算符右边最近的两个数字做运算,结果作为新的字符记录下来。
一直扫描到表达式的最左端时,最后运算的值也就是表达式的值。
- 后序表达式(逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法)
后序表达式所有的操作符置于操作数后面,因此也被称为后缀表示法。逆波兰表示法不需要括号标识操作符的优先级。
eg:
中序表达式: (1+4)*3+10/5
后序表达式: 1 4 + 3 * 10 5 / +
后序表达式的计算:
eg:
1 4 + 3 * 10 5 / +
step1: 1 + 4 => 5
new expression: 5 3 * 10 5 / +
step2: 5 * 3 => 15
new expression: 15 10 5 / +
step3: 10 / 5 => 2
new expression: 15 2 +
step4: 15 + 2 => 17
后序表达式的求值:
后序表达式的求值和前序表达式十分相似,后序表达式是从左至右扫描表达式,从左边第一个字符开始判断,如果的那个字符是数字继续扫描,
如果是运算符,将运算符左边最近的两个数字做运算,结果作为新的字符记录下来。一直扫描到表达式的最右端时,最后运算的值也就是表达式的值。
中序表达式转后序表达式(暂时只实现四则运算级别的转化)
- 创建一个队列和一个操作符栈
- 遇到操作数则送入队列
- 遇到操作符则送入栈
- 遇到加减乘除运算符:弹出所有优先级大于或等于该运算符的栈顶元素,然后该运算符入栈
- 遇到”(“括号直接入栈
- 遇到”)"括号则将栈内直到“(”括号的所有操作符送入队列
- 执行完成后,先输出队列内容,在输出栈内容,最终结果即是后序表达式
/**
* 先序表达式 -> 后序表达式
*/
public String infixToPostfix(String[] elements) {
String res = "";
Stack<String> stack = new Stack<>();
Queue<String> queue = new Queue<>();
for (int i = 0; i < elements.length; i++) {
String s = elements[i];
if (s.equals("(")) {
stack.push(s);
continue;
}
if (s.equals(")")) {
String pop = stack.pop();
while (!pop.equals("(")) {
queue.enqueue(pop);
pop = stack.pop();
}
continue;
}
//碰到"+"或 "-"运算符
if (s.equals("+") || s.equals("-")){
if (stack.isEmpty()){
stack.push(s);
continue;
}
while (!stack.isEmpty() && !stack.peek().equals("(")){
queue.enqueue(stack.pop());
}
stack.push(s);
continue;
}
//碰到"*"或 "/"运算符
if (s.equals("*") || s.equals("/")){
if (stack.isEmpty()){
stack.push(s);
continue;
}
boolean peek = stack.peek().equals("*") || stack.peek().equals("/");
while (!stack.isEmpty() && peek) {
queue.enqueue(stack.pop());
}
stack.push(s);
continue;
}
queue.enqueue(s);
}
//拼接后序表达式
do{
res += queue.dequeue() + " ";
} while (!queue.isEmpty());
do {
res += stack.pop() + " ";
} while (!stack.isEmpty());
return res;
}
后序表达式的计算(暂时只实现了四则运算)
- 从左至右扫描表达式
- 如果字符是数字继续扫描,如果是操作符,取左边最近的两个操作数,运算后将结果压入栈中
- 扫描到表达式的最右端时,最后运算的值也就是表达式的值
/**
* 1.3.11 计算后序表达式的值
*/
public class EvaluatePostfix {
public int evaluate(String[] postfix){
Stack<String> stack = new Stack<>();
for (int i = postfix.length - 1; i >= 0; i--) {
stack.push(postfix[i]);
}
Stack<String> tmp = new Stack<>();
String res = "";
while (!stack.isEmpty()) {
String pop = stack.pop();
if (pop.equals("*") || pop.equals("/") || pop.equals("+") || pop.equals("-")){
int rightValue = Integer.valueOf(tmp.pop());
int leftValue = Integer.valueOf(tmp.pop());
int sum = evaluate(leftValue, rightValue, pop);
stack.push(sum + "");
while (!tmp.isEmpty()){
stack.push(tmp.pop());
}
continue;
}
tmp.push(pop);
res = pop;
}
return Integer.parseInt(res);
}
public int evaluate(int a, int b, String operator){
switch (operator){
case "*" : return a * b;
case "/" : return a / b;
case "+" : return a + b;
case "-" : return a - b;
default: throw new IllegalArgumentException("operator must be \"* / + -\"");
}
}
}