逆波蘭計算器分析與實現

定義

邏輯提問式類似於算術表示式,對於檢索而言,這種表示式並不是最優和最簡潔的形式,需要進行必要的轉換。1929年波蘭的邏輯學家盧卡西維茲(Jan Lucasiewicz)提出了將運算子放在運算項後面的邏輯表示式,又稱“逆波蘭表示式”。採用這種表示式組織邏輯提問式非常方便檢索運算,是日本的福島先生最早將逆波蘭表示式應用於情報檢索的,故又稱為“福島方法”。

逆波蘭表示式又叫做字尾表示式,是一種沒有括號,並嚴格遵循“從左到右”運算的字尾式表達方法,如下表所示:

逆波蘭計算器分析與實現

逆波蘭表示式

演算法步驟

1、首先構造一個運算子棧,此運算子在棧內遵循越往棧頂優先順序越高的原則。

2、讀入一個用中綴表示的簡單算術表示式,為方便起見,設該簡單算術表示式的右端多加上了優先順序最低的特殊符號“#”。

3、從左至右掃描該算術表示式,從第一個字元開始判斷,如果該字元是數字,則分析到該數字串的結束並將該數字串直接輸出。

4、如果不是數字,該字元則是運算子,此時需比較優先關係。

具體做法是:將該字元與運算子棧頂的運算子的優先關係相比較。如果該字元優先關係高於此運算子棧頂的運算子,則將該運算子入棧。若不是的話,則將棧頂的運算子從棧中彈出,直到棧項運算子的優先順序低於當前運算子,將該字元入棧。

5、重複步驟1~2,直至掃描完整個簡單算術表示式,確定所有字元都得到正確處理,便可以將中綴式表示的簡單算術表示式轉化為逆波蘭表示的簡單算術表示式。

程式碼實現

package com。zyp。joseph;import org。springframework。util。ObjectUtils;import java。util。ArrayList;import java。util。List;import java。util。Stack;/** * 逆波蘭計算器實現 * @author zyp * @create 2022/1/11 */public class InversePolishCalculator { public static void main(String[] args){ //中綴表示式 String str = “(3+4)*5-6”; //將字串放入list中 List infixList = toList(str); //將中綴字串轉為字尾字串 List suffixList = infixToSuffixExpression(infixList); //計算結果 int total = calculationResults(suffixList); System。out。println(“逆波蘭表示式計算結果為:”+total); } /** * 將字串放入List中 * @param str * @return */ public static List toList(String str){ List list = new ArrayList<>(); int i = 0; String sb = “”; while(i < str。length()){ if((str。charAt(i)+“”)。matches(“\\d”)){ if(i == str。length()-1){ list。add(“”+str。charAt(i)); break; } sb += str。charAt(i); }else{ if(!ObjectUtils。isEmpty(sb)){ list。add(sb); sb = “”; } list。add(“”+str。charAt(i)); } i++; } return list; } /** * 中綴表示式轉字尾表示式 * @param arrayList * @return */ public static List infixToSuffixExpression(List arrayList){ List list = new ArrayList<>(); //使用者儲存臨時符號 Stack symbolStack = new Stack<>(); for(String str : arrayList){ if(str。matches(“\\d+”)){ list。add(str); }else{ compareSymbolPriority(symbolStack,str,list); } } while(!symbolStack。empty()){ list。add(symbolStack。pop()); } return list; } /** * 比較符號優先順序 * @return */ public static void compareSymbolPriority(Stack symbolStack,String symbolStr,List list) { if (symbolStack。empty()) { symbolStack。push(symbolStr); } else { String peek = symbolStack。peek(); //遇到棧中中“(”直接加入 if (“+”。equals(symbolStr) || “-”。equals(symbolStr)) { if(“(”。equals(peek)){ symbolStack。push(symbolStr); }else{ //代表優先順序比符號棧中的小或者等於 list。add(symbolStack。pop()); //繼續比較優先順序 compareSymbolPriority(symbolStack, symbolStr, list); } } else if (“(”。equals(symbolStr)) { symbolStack。push(symbolStr); } else if (“*”。equals(symbolStr) || “/”。equals(symbolStr)) { symbolStack。push(symbolStr); //直到消除括號為止 } else if (“)”。equals(symbolStr)) { if (“(”。equals(peek)) { symbolStack。pop(); } else { list。add(symbolStack。pop()); compareSymbolPriority(symbolStack, symbolStr, list); } } } } /** * 計算結果 * @param list * @return */ public static int calculationResults(List list){ Stack stack = new Stack<>(); for(String str : list){ if(str。matches(“\\d+”)){ stack。push(str); }else{ int total = 0; int num1 = Integer。parseInt(stack。pop()); int num2 = Integer。parseInt(stack。pop()); if(“+”。equals(str)){ total = num2 + num1; }else if(“-”。equals(str)){ total = num2 - num1; }else if(“*”。equals(str)){ total = num2 * num1; }else if(“/”。equals(str)){ total = num2 / num1; } stack。push(“”+total); } } return Integer。parseInt(stack。pop()); }}

程式碼分析

1。中綴表示式轉List

首先將字串轉為字元

遍歷字元如果是數字先將數字存到一個變數中,直到遇到符號的時候,將數字加入列表,再將符號加入列表

如果到最後一個將數字加入列表中

2。List轉字尾表示式

首先遍歷列表,是數字直接加入到List中,如果是符號分以下幾種情況當符號為:

“(”:直接加入到棧中

“)”:依次將棧中的符號彈出,加入到List中

“+”、“-”、“*”、“/”:和棧頂比較符號優先順序,如果優先順序大於棧頂直接入棧,如果小於或者等於將棧頂彈出,加入List中,繼續和下一個棧頂做比較(如果遇到棧為空或者棧頂為“(”就直接入棧)

最後將棧中的符號依次彈出,加入到List中

3。計算結果(通過後綴表示式列表計算結果)

遍歷列表,如果是數字將數字加入到棧中,遇到符號依次從棧中彈出兩個數字,並根據符號進行計算,將計算結果入棧,直到迴圈結束,將棧中的結果彈出