[Code] 中綴式轉後綴式
阿新 • • 發佈:2018-02-12
棧操作 ins 1.2 yml scanner ycm hbm ava -c
[Code] 中綴式轉後綴式
概要
對於一個可帶括號的中綴四則運算表達式, 例如30 + 4 / 2
或 30 / ( 4 + 2 )
, 下面代碼將分別轉換為對應的後綴表達形式 30 4 2 / +
和 30 4 2 + /
. 要求每個 token 之間以若幹個空白符隔開, 輸入的中綴式為單行.
代碼
import java.util.Scanner;
import java.util.Deque;
import java.util.ArrayDeque;
import java.util.Map;
public class Convertor {
public static void main(String[] main) {
Scanner in = new Scanner(System.in);
String expression = in.nextLine();
expression = "( " + expression + " )";
String[] tokens = expression.split("\\s+");
Deque<String> opStack = new ArrayDeque<>();
Deque<String> nuStack = new ArrayDeque<>();
Map<String, Integer> opPriority =
Map.of("+" , 0, "-", 0, "*", 1, "/", 1, "(", -1);
for (String token: tokens) {
if (token.equals("(")) {
opStack.addFirst(token);
} else if (token.equals(")")) {
while (!opStack.peekFirst().equals("(")) {
produceOne(opStack, nuStack);
}
opStack.removeFirst();
} else if (opPriority.containsKey(token)) {
while ((!opStack.isEmpty()) && (opPriority.get(token) <= opPriority.get(opStack.peekFirst()))) {
produceOne(opStack, nuStack);
}
opStack.addFirst(token);
} else { // number
nuStack.addFirst(token);
}
}
System.out.println(nuStack.removeFirst().replaceAll("\\s+", " ").trim());
}
private static void produceOne(Deque<String> opStack, Deque<String> nuStack) {
String production = filter(nuStack.removeFirst()) + " ";
production = filter(nuStack.removeFirst()) + " " + production + " ";
production = production + " " + opStack.removeFirst() + " ";
nuStack.addFirst(production);
}
private static String filter(String token) {
return token.equals("@") ? "" : token;
}
}
分析
- 為了統一處理(避免分類討論), 對於輸入的中綴表達式直接加上兩端的括號. 這樣的操作並不會影響整個求解的結果, 而不加這個括號需要額外處理最終操作符棧剩余的操作符.
- 逐個 token 處理,
- 對於操作數, 直接入棧.
- 左右括號配對處理.
- 對於一般的操作符, 在此處充當 trigger 的作用. 邏輯上, 第一個操作符入棧, 對於後續的操作符, 先逐個彈出操作符棧中優先級不小於當前操作符的運算符以及相應的操作數, 在將當前的操作符入棧. 彈出優先級大的操作符是顯然的, 彈出優先級相等的操作符是由於要滿足左結合性, 若是右結合操作符, 則不彈出. 註意彈出操作符並產生代表運算結果的字符串後仍需將其當做結果壓回操作數棧中.
- 細節上,
- 使用 Java 9 的
Map.of
函數簡化opPriority
字典的構建代碼. - 使用效率更高實現更完備的
Deque
並將操作限制在棧操作上以代替不再推薦的Stack
. - 為了簡化討論, 將
(
的優先級定義為最低. - 為了簡化討論, 先在各結果 token 之間插入若幹個空白符, 輸出時再統一壓縮多余的空白符.
- 使用 Java 9 的
- 假定輸入都是合法的, 沒有對不滿足概要中假設的前提的非法輸入進行處理.
[Code] 中綴式轉後綴式