中綴表示式(算數表示式)轉成字首表示式(波蘭表示式)並求計算值
阿新 • • 發佈:2021-01-29
技術標籤: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()));
}
}