與轉換爲前綴表達式相似,遵循以下步驟:
(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中的元素並輸出,結果的逆序即爲中綴表達式對應的後綴表達式(轉換爲前綴表達式時不用逆序)。
import java.util.Stack;
public class Calculator {
public static void main(String[] args) {
suffixCalc("1+((2+3)*4)-5");
}
public static void suffixCalc(String input) {
Stack<Double> numbersStack = new Stack<Double>();
Stack<Character> operatorsStack = new Stack<Character>();
Stack<Object> suffixExpr = new Stack<Object>();
int len = input.length();
char c, temp;
double number;
for (int i = 0; i < len; i++) {
c = input.charAt(i);
if (Character.isDigit(c)) {
int endDigitPos = getEndPosOfDigit(input, i);
number = Double.parseDouble(input.substring(i, endDigitPos));
i = endDigitPos - 1;
numbersStack.push(number);
if ((int)number == number) {
suffixExpr.push((int)number);
} else {
suffixExpr.push(number);
}
} else if (isOperator(c)) {
// 操作符棧非空,且棧頂不是'(',且當前操作符優先級低於棧頂操作符
while (!operatorsStack.isEmpty()
&& operatorsStack.peek() != '('
&& priorityCompare(c, operatorsStack.peek()) <= 0) {
suffixExpr.push(operatorsStack.peek());
numbersStack.push(calc(numbersStack, operatorsStack.pop()));
}
operatorsStack.push(c);
} else if (c == '(') {
operatorsStack.push(c);
} else if (c == ')') {
while ((temp = operatorsStack.pop()) != '(') {
numbersStack.push(calc(numbersStack, temp));
suffixExpr.push(temp);
}
} else if (c == ' ') {
} else {
throw new IllegalArgumentException("wrong character '" + c + "'");
}
}
while (!operatorsStack.isEmpty()) {
temp = operatorsStack.pop();
suffixExpr.push(temp);
numbersStack.push(calc(numbersStack, temp));
}
printStack(suffixExpr);
System.out.println("\ncalc result\t" + numbersStack.pop());
}
private static void printStack(Stack<?> stack) {
String s = "";
while (!stack.isEmpty()) {
s += stack.pop();
}
for (int i = s.length()-1; i >= 0; i--) {
System.out.print(s.charAt(i)+" ");
}
}
private static int getEndPosOfDigit(String input, int start) {
char c;
int end = start + 1;
for (int i = start + 1; i < input.length(); i++) {
c = input.charAt(i);
if (Character.isDigit(c) || c == '.') {
continue;
} else {
end = i;
break;
}
}
return end;
}
private static boolean isOperator(char c) {
return (c == '+' || c == '-' || c == '*' || c == '/');
}
// op1優先級高於op2 return 1
private static int priorityCompare(char op1, char op2) {
switch (op1) {
case '+':
case '-':
return (op2 == '*' || op2 == '/' ? -1 : 0);
case '*':
case '/':
return (op2 == '+' || op2 == '-' ? 1 : 0);
}
return 1;
}
private static double calc(Stack<Double> numbersStack, char op) {
double num1 = numbersStack.pop();
double num2 = numbersStack.pop();
return calc(num2, num1, op);
}
private static double calc(double num1, double num2, char op) throws IllegalArgumentException {
switch (op) {
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
case '/':
if (num2 == 0)
throw new IllegalArgumentException("divisor can't be 0.");
return num1 / num2;
default:
return 0;
}
}
}
output:
1 2 3 + 4 * + 5 -
calc result 16.0