前序表達式 , 中序表達式 , 后序表達式
-
中序表達式
中序表達式即我們日常使用的表達式,從左往右閱讀,結構清晰,但是需要括號改變優先級,對計算機不友好
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 \"* / + -\"");
}
}
}