1. 程式人生 > 其它 >中綴表示式(算數表示式)轉成字首表示式(波蘭表示式)並求計算值

中綴表示式(算數表示式)轉成字首表示式(波蘭表示式)並求計算值

技術標籤:Java資料結構Java資料結構stackHashSetjava字首表示式

一、求字首表示式計算值

(1)從右到左掃描表示式,遇到數字時直接入棧,遇到運算子時彈出棧頂兩個數;
(2)根據運算子對兩個數進行相應計算(棧頂元素 op 次頂元素),並將計算結果入棧;
(3)重複上述過程直至表示式的最左端,剩餘最後一個數在棧中彈出即為最終計算結果。

二、中綴表示式轉換為字首表示式

(1) 初始化兩個棧:運算子棧S1和儲存中間結果的棧S2;
(2) 從右至左掃描中綴表示式;
(3) 遇到運算元時,將其壓入S2;
(4) 遇到運算子時,比較其與S1棧頂運算子的優先順序:
(4-1) 如果S1為空,或棧頂運算子為右括號“)”,則直接將此運算子入棧;

(4-2) 否則,若優先順序比棧頂運算子的較高或相等,也將運算子壓入S1;
(4-3) 否則,將S1棧頂的運算子彈出並壓入到S2中,再次轉到(4-1)與S1中新的棧頂運算子相比較;
(5) 遇到括號時:
(5-1) 如果是右括號“)”,則直接壓入S1;
(5-2) 如果是左括號“(”,則依次彈出S1棧頂的運算子,並壓入S2,直到遇到右括號為止,此時將這一對括號丟棄;
(6) 重複步驟(2)至(5),直到表示式的最左邊;
(7) 將S1中剩餘的運算子依次彈出並壓入S2;
(8) 依次彈出S2中的元素並輸出,結果即為中綴表示式對應的字首表示式。

三、程式碼完整實現

package fighting;
import java.util.Scanner; import java.util.Stack; import java.util.HashSet; public class fighting{ private static HashSet<Character> oper=new HashSet<>();//操作符棧 private static void initOper() {//初始化操作符,將加減乘除操作符全放入HashSet中 oper.add('+'); oper.add('-'); oper.add('*'); oper.add('/'
); } private static boolean isOper(char c) {//判斷字元是否為操作符 if(oper.contains(c)) { return true; } return false; } private static boolean isNum(char c) {//判斷字元是否為運算元 if(c>='0'&&c<='9') { return true; } return false; } private static int priority(char c) {//獲取各操作符的優先順序,數值越大優先順序越高 switch(c) { case '*': case '/': return 3; case '+': case '-': return 2; case ')': return 1; default: System.out.println("輸入錯誤!"); return 0; } } public static int calculate(String str) {//計算字首表示式的值 Stack<Integer> numStack=new Stack<>();//運算元棧 char c;//遍歷表示式時的某個位置的字元 int num1,num2;//出棧的運算元 for(int i=str.length()-1;i>=0;i--) {//從右到左遍歷表示式 if(isNum(c=str.charAt(i))) { numStack.push(c-'0');//遇到運算元直接入棧,因為此處的c為字元,需要將字元型數字轉為整型數字即進行ASCII碼轉換 }else { num1=numStack.pop();//棧頂元素 num2=numStack.pop();//次棧頂元素 switch(c) { case '+': numStack.push(num1+num2); break; case '-': numStack.push(num1-num2); break; case '*': numStack.push(num1*num2); break; case '/': if(num2!=0) { numStack.push(num1/num2); }else { throw new RuntimeException("除數不能為零!");//除數為零時丟擲異常 } break; } } } return numStack.pop();//運算元棧中只剩下最終的計算結果,出棧即可 } public static void main(String[] args) { initOper(); System.out.println("請輸入表示式:"); Scanner sc=new Scanner(System.in); String expression=sc.nextLine();//輸入的表示式 StringBuilder prefinExpression=new StringBuilder();//儲存字首表示式 Stack<Character> oper=new Stack<>();//操作符棧 char c;//遍歷表示式時的某個位置的字元 char pop;//操作符棧中彈出的字元 for(int i=expression.length()-1;i>=0;i--) { c=expression.charAt(i); if(isNum(c)) { prefinExpression.append(c);//遇到運算元直接放入字首表示式中 }else if(isOper(c)) { if(oper.isEmpty()) {//遇到操作符若棧為空時直接入棧 oper.push(c); }else {//棧不為空時 while(true) { if(oper.isEmpty()||priority(oper.peek())<=priority(c)) { break; } pop=oper.pop();//若棧頂元素優先順序高於當前操作符,則將棧頂元素出棧並放入字首表示式中 prefinExpression.append(pop); } oper.push(c);//若棧頂元素優先順序小於等於當前操作符,則將操作符入棧 } }else if(')'==c) {//遇到右括號直接入棧 oper.push(c); }else if('('==c) { while((pop=oper.pop())!=')') {//遇到的是'(',將棧中運算子依次彈出,放入字首表示式中,直到遇到第一個')'。(注意:彈出的‘)’應當丟棄)); prefinExpression.append(pop); } }else { System.out.println("輸入表示式有誤!"); } } while(!oper.isEmpty()) {//遍歷完成後將棧中所有元素出棧並加入字首表示式當中 prefinExpression.append(oper.pop()); } prefinExpression=prefinExpression.reverse();//將字首表示式逆序輸出才為最終字首表示式 System.out.println("轉換後的字首表示式為:"+prefinExpression.toString()); System.out.println("字首表示式計算的結果為:"+calculate(prefinExpression.toString())); } }

執行結果:
在這裡插入圖片描述
中綴表示式(算數表示式)轉成字尾表示式(逆波蘭表示式)並求計算值