与转换为前缀表达式相似,遵循以下步骤:
(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