中缀表达式计算器
题目要求:输入一个简单中缀表达式,计算其结果。(以"(10+40/2*3)/2+8")为例) 注意输入只能是简单的四则运算。
算法思路流程:
- 第一步:格式化表达式,因为在我们的表达式中会存在两位数或者三位数,当我们进行字符串分割时会导致我们得到表达式与需要计算的表达式不匹配。
private static String insertBlanks(String expression){
StringBuilder sb = new StringBuilder();
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
if (c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/'){
sb.append(" ");
sb.append(c);
sb.append(" ");
}else{
sb.append(c);
}
}
return sb.toString();
}
- 定义两个栈,一个操作符栈,一个数字栈,遍历格式化后的表达式:
注意在格式化结束表达式时:需要过滤掉空串;因为在格式化时")"后紧接着又是一个操作符这样在格式化时会插入两个空串,那么在分割时一定会多余产生一个空串:
System.out.println(expression);
//格式化表达式
expression = insertBlanks(expression);
String[] tokens = expression.split(" ");
for(String a :tokens){
System.out.print("\'"+a+"\'");
}
输出结果如下:
所以在计算之前我们需要过滤掉空串
3.遍历过滤后的空串:
- 当遇到数字时,直接进栈
- 当遇到操作符时
* 若操作符栈为空直接进栈
* 若操作符栈,栈顶为"(" 直接进
* 若操作符栈中为其他操作符时: 如果当前操作符比栈顶的操作符的优先级大时,则进栈;若栈顶的操作符优先级比当前操作符优先级大或相等时,将操作符栈中所有比当前操作符优先级大或相等的进行弹栈计算处理掉,直到遇到"("或者比当前操作符优先级小的为止 - 当前操作符是")"时将操作符栈中’’(“上面的所有操作符处理掉,最终弹出”("即可。
注意:在进行计算时先弹出数字栈中的元素首先弹出的元素放在操作符右边后弹出的放在左边,并将计算后的结果在进数字栈
整体代码如下:
public class InfixCalculator {
public static void main(String[] args) {
String expression = "(10+20/2*3)/2+8"; //结果为28
try {
int result = evaluateExpression(expression);
System.out.println(result);
}catch (Exception e){
e.printStackTrace();
System.out.println("Wrong expression");
}
}
private static int evaluateExpression(String expression) {
System.out.println(expression);
//定义两个辅助栈
ArrayStack<Character> operatorStack = new ArrayStack<Character>();
ArrayStack<Integer> numberStack = new ArrayStack<Integer>();
//格式化表达式
expression = insertBlanks(expression);
String[] tokens = expression.split(" "); //利用String中的split方法对字符数组进行分割
for(String a :tokens){
System.out.print("\'"+a+"\'");
}
for (String token :tokens){
//过滤空串
if (token.length()==0){
continue;
//遍历到+-号
}else if(token.equals("+") || token.equals('-')){
while ((!operatorStack.isEmpty()) && (operatorStack.peek() == '+' || operatorStack.peek() == '-' ||
operatorStack.peek() == '*' || operatorStack.peek() == '/')){
//如果是之前的+-*/ 则进行弹栈并计算
processAnOperator(numberStack, operatorStack);
}
//如果操作符栈为空 或者 不为空但栈顶为(
operatorStack.push(token.charAt(0));
//遍历到 * / 号
}else if (token.equals("*") || token.equals("/")){
while (!operatorStack.isEmpty() && (operatorStack.peek() == '*' || operatorStack.peek() == '/')) {
//如果之前是别的* / 则需要弹栈 并计算
processAnOperator(numberStack,operatorStack);
}
//如果操作符栈为空 或者 不为空但栈顶为(
operatorStack.push(token.charAt(0));
//遍历到 (
}else if(token.equals("(")){
operatorStack.push(token.charAt(0));
//遍历到 )
}else if (token.equals(")")){
while(operatorStack.peek() != '('){
//只要操作符栈的栈顶不是做括号 便依次进行弹栈计算
processAnOperator(numberStack,operatorStack);
}
//最后 弹出左括号
operatorStack.pop();
}else{
//遍历到数字 将其进栈到数字栈中
numberStack.push(Integer.parseInt(token));
}
}
//处理掉最后的操作符
while (!operatorStack.isEmpty()){
processAnOperator(numberStack,operatorStack);
}
return numberStack.pop();
}
//操作符栈弹栈一个元素 数字栈弹栈两个数字 进行计算 并将新的结果进栈到数字栈
private static void processAnOperator(ArrayStack<Integer> numberStack, ArrayStack<Character> operatorStack) {
char op = operatorStack.pop();
int num1 = numberStack.pop();
int num2 = numberStack.pop();
if (op == '+'){
numberStack.push(num2+num1);
}else if(op == '-'){
numberStack.push(num2 - num1);
}else if(op == '*'){
numberStack.push(num2 * num1);
}else if (op == '/'){
numberStack.push(num2 / num1);
}
}
//对原表达式 进行格式化处理 给所有的非数字字符两边添加空格
private static String insertBlanks(String expression){
StringBuilder sb = new StringBuilder();
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
if (c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/'){
sb.append(" ");
sb.append(c);
sb.append(" ");
}else{
sb.append(c);
}
}
return sb.toString();
}
}