计算机进行运算并不是按照中缀表达式来进行运算的,而是按照后缀表达式。
如何将中缀表达式转换为前缀、后缀表达式。例如式子:1 + 2 * (9 - (6-4) *2 + 5),按照运算顺序将每一步都加上括号 (1 + (2 * (((9 - ((6-4) *2)) + 5)))),再将运算符号移到括号的前面和后面,+(1 *(2 +((-(9 *(-(64) 2)) 5)))) ,(1 (2 (((9 ((6 4) - 2)*) - 5))+)*)+ , 再去掉括号就成了前缀表达式和后缀表示式,+1 *2 +-9 *-64 2 5 , 1 2 9 6 4 - 2 * - 5 + * +。
算法描述
第一步:扫描字符串,去除空格。
第二步:遍历字符串,操作数直接入队列,
运算符:“+ - * / ”
栈顶元素first与入栈运算符current作优先级比较,若priority(first) >= priority(current),则入栈,反之first出栈,加入队列
左括号:" ( "
直接入栈
右括号: " ) "
扫描栈,将栈里元素出栈,加入队列,直到扫描碰到左括号,并将左括号出栈。
第三步:遍历队列,操作数直接入栈,碰到运算符ch则将栈顶操作数n1,n2出栈,运算operate(n2,n1,ch),再将结果入栈,重复第三步。
代码实现
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
String s = "1 + 2 * (9 - (6-4) *2 + 5)";
Calculator calc = new Calculator();
Object[] exp = calc.compile(s);
int result = calc.calculate(exp);
System.out.println(s + " => " + expressionToString(exp) + " => " + result);
}
static String expressionToString(Object[] exp) {
List<String> list = new ArrayList<>(exp.length);
for (Object e : exp) {
list.add(e.toString());
}
return String.join(" ", list);
}
}
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
public class Calculator {
public Object[] compile(String s) {
Object[] parsed = parseAsExpression(s);
List<Object> output = new LinkedList<>();
Deque<Character> stack = new LinkedList<>();
for (Object e : parsed) {
if (e instanceof Integer) {
output.add(e);
} else {
char ch = (Character) e;
switch (ch) {
case ')':
// find '(' in stack:
for (;;) {
if (stack.isEmpty()) {
throw new IllegalStateException("Compile error: " + s);
}
char top = stack.pop();
if (top == '(') {
break;
} else {
output.add(top);
}
}
break;
case '(':
stack.push(ch);
break;
case '+':
case '-':
case '*':
case '/':
// find all operators that >= ch:
while (!stack.isEmpty()) {
char first = stack.peek();
if (priority(first) >= priority(ch)) {
stack.pop();
output.add(first);
} else {
break;
}
}
stack.push(ch);
break;
default:
throw new IllegalStateException("Compile error: " + s);
}
}
}
while (!stack.isEmpty()) {
output.add(stack.pop());
}
return output.toArray();
}
public int calculate(Object[] expression) {
Deque<Integer> stack = new LinkedList<>();
for (Object e : expression) {
if (e instanceof Integer) {
stack.push((Integer) e);
} else {
char op = (Character) e;
int n1 = stack.pop();
int n2 = stack.pop();
int r = operate(op, n2, n1);
stack.push(r);
}
}
return stack.pop();
}
Object[] parseAsExpression(String s) {
List<Object> list = new ArrayList<>();
for (char ch : s.toCharArray()) {
if (ch >= '0' && ch <= '9') {
int n = Integer.parseInt(String.valueOf(ch));
list.add(n);
} else if ("+-*/()".indexOf(ch) != (-1)) {
list.add(ch);
} else if (ch == ' ') {
// ignore white space
} else {
throw new IllegalArgumentException("Compile error: invalid char \'" + ch + "\'");
}
}
return list.toArray();
}
// priority from high to low: '*', '/' > '+', '-' > '('
int priority(char op) {
switch (op) {
case '*':
case '/':
return 2;
case '+':
case '-':
return 1;
case '(':
return 0;
default:
throw new IllegalArgumentException("bad operator: " + op);
}
}
int operate(char operator, int a, int b) {
switch (operator) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
return a / b;
default:
throw new UnsupportedOperationException();
}
}
}