设计数据结构与算法,计算算数表达式,需要支持:
- 基本计算,加减乘除,满足计算优先级 例如输入 30+3+8+91 输出20
- 括号,支持括号,例如输入 3+(3-0)*2 输出 9
- 假设所有的数字均为整数,无需考虑精度问题
要求:
- 输入的表达式是字符串类型String。
- 对于操作数要求不止一位,这里对字符串里面解析出操作数有要求。需要有从表达式里面解析出完整操作数的能力。
- 代码结构要求具备一定的面向对象原则,能够定义出表达式,操作数,运算符等对象。
- 提供基本的测试。
/**
* 运算引擎
*/
public class CalculateEngine {
/**
* 操作符栈
*/
private Stack<String> operatorStack;
/**
* 操作数栈
*/
private Stack<Integer> operateNumberStack;
/**
* 后缀表达式输出
*/
private StringBuilder output;
public CalculateEngine() {
operatorStack = new Stack<>();
operateNumberStack = new Stack<>();
output = new StringBuilder();
}
/**
* 表达式计算
* @param infixExpression
* @return
*/
public Integer eval(String infixExpression) {
String postfixExpression = toPostfixExpression(infixExpression);
return calculatePostfixExpression(postfixExpression);
}
/**
* 中缀表达式转后缀表达式
* @param infixExpression
* @return
*/
private String toPostfixExpression(String infixExpression) {
infixExpression = formatInfixExpression(infixExpression);
//System.out.println("Formatted Infix Expression: " + infixExpression);
String[] infixExpressionArray = infixExpression.split(" ");//split("\\+|-|\\*|/|\\(|\\)");
Operator operator = null, topOperator = null;
String topSymbol = null;
for (String item : infixExpressionArray) {
if (item == null || item.trim().equals("")) {
continue;
}
// item为操作符,比较与栈顶操作符的优先级
if ((operator = Operator.from(item)) != null) {
// 操作符栈为空直接压栈
if (operatorStack.isEmpty()) {
operatorStack.push(item);
} else {
// item为右括号,将操作符栈输出,直到输出为左括号为止
if (operator == Operator.RIGHT_BRACKETS) {
topSymbol = operatorStack.pop();
topOperator = Operator.from(topSymbol);
while (topOperator != Operator.LEFT_BRACKETS) {
appendOutput(topSymbol);
topSymbol = operatorStack.pop();
topOperator = Operator.from(topSymbol);
}
} else {
topSymbol = operatorStack.peek();
topOperator = Operator.from(topSymbol);
// 栈顶操作不为左括号 && 栈顶操作符优先级 >= 当前操作符优先级,出栈输出到后缀表达式
if (operator != Operator.LEFT_BRACKETS && topOperator.priority() >= operator.priority() && topSymbol.equals(operatorStack.pop())) {
appendOutput(topSymbol);
}
operatorStack.push(item);
}
}
} else {
// 数字直接输出
appendOutput(item);
}
}
// 输出操作符栈的剩余操作符到后缀表达式中
while (!operatorStack.isEmpty()) {
topSymbol = operatorStack.pop();
appendOutput(topSymbol);
}
//System.out.println("Postfix Expression: " + output.toString());
return output.toString();
}
/**
* 格式化中缀表达式
* @param infixExpression
* @return
*/
private String formatInfixExpression(String infixExpression) {
infixExpression = infixExpression.replace(" ", "");
infixExpression = infixExpression.replace("+", " + ");
infixExpression = infixExpression.replace("-", " - ");
infixExpression = infixExpression.replace("*", " * ");
infixExpression = infixExpression.replace("/", " / ");
infixExpression = infixExpression.replace("+", " + ");
infixExpression = infixExpression.replace("(", "( ");
infixExpression = infixExpression.replace(")", " )");
infixExpression = infixExpression.replace("(", "( ");
infixExpression = infixExpression.replace(")", " )");
return infixExpression;
}
/**
* 后缀表达式附加
* @param item
*/
private void appendOutput(String item) {
if (output.length() > 0) {
output.append(" ");
}
output.append(item);
}
/**
* 后缀表达式结果计算
* @param postfixExpression
* @return
*/
private Integer calculatePostfixExpression(String postfixExpression) {
String[] postfixExpressionArray = postfixExpression.split(" ");
Operator operator;
Integer result = null;
String item;
for (int i = 0; i < postfixExpressionArray.length; i++) {
item = postfixExpressionArray[i];
// 如果item为操作符则从操作数栈去出栈2个操作数计算结果,将结果压栈
if ((operator = Operator.from(item)) != null) {
Integer secondOperateNumber = operateNumberStack.pop();
Integer firstOperateNumber = operateNumberStack.pop();
Operation operation = OperationFactory.get(operator);
result = operation.getResult(firstOperateNumber, secondOperateNumber);
if (i < postfixExpressionArray.length - 1) {
operateNumberStack.push(result);
}
}
// 如果item为操作数直接压栈
else {
operateNumberStack.push(Integer.valueOf(item));
}
}
return result;
}
}
/**
* 操作符
*/
public enum Operator {
PLUS("+", 1),
SUBTRACT("-", 1),
MULTIPLY("*", 2),
DIVIDE("/", 2),
LEFT_BRACKETS("(", 0),
RIGHT_BRACKETS(")", 3);
private String symbol;
private int priority;
Operator(String symbol, int priority) {
this.symbol = symbol;
this.priority = priority;
}
public String symbol() {
return symbol;
}
public int priority() {
return priority;
}
public Operator of(String symbol) {
for (Operator operator : values()) {
if (operator.symbol.equals(symbol)) {
return operator;
}
}
throw new IllegalArgumentException("invalid symbol: " + symbol);
}
public static Operator from(String symbol) {
for (Operator operator : values()) {
if (operator.symbol.equals(symbol)) {
return operator;
}
}
return null;
}
}
import com.ant.interview.expression.operation.*;
import java.util.HashMap;
import java.util.Map;
/**
* 运算工厂
*/
public class OperationFactory {
private static final Map<Operator, Operation> operationMap = new HashMap<Operator, Operation>(4) {
{
put(Operator.PLUS, new PlusOperation());
put(Operator.SUBTRACT, new SubtractOperation());
put(Operator.MULTIPLY, new MultiplyOperation());
put(Operator.DIVIDE, new DivideOperation());
}
};
public static Operation get(Operator operator) {
return operationMap.get(operator);
}
}
public interface Operation {
Integer getResult(Integer firstOperateNumber, Integer secondOperateNumber);
}
/**
* 加法运算
*/
public class PlusOperation implements Operation {
@Override
public Integer getResult(Integer firstOperateNumber, Integer secondOperateNumber) {
Integer result = firstOperateNumber.intValue() + secondOperateNumber.intValue();
//System.out.println(String.format("%d + %d = %d", firstOperateNumber.intValue(), secondOperateNumber.intValue(), result.intValue()));
return result;
}
}
/**
* 减法运算
*/
public class SubtractOperation implements Operation {
@Override
public Integer getResult(Integer firstOperateNumber, Integer secondOperateNumber) {
Integer result = firstOperateNumber.intValue() - secondOperateNumber.intValue();
//System.out.println(String.format("%d - %d = %d", firstOperateNumber.intValue(), secondOperateNumber.intValue(), result.intValue()));
return result;
}
}
/**
* 乘法运算
*/
public class MultiplyOperation implements Operation {
@Override
public Integer getResult(Integer firstOperateNumber, Integer secondOperateNumber) {
Integer result = firstOperateNumber.intValue() * secondOperateNumber.intValue();
//System.out.println(String.format("%d * %d = %d", firstOperateNumber.intValue(), secondOperateNumber.intValue(), result.intValue()));
return result;
}
}
/**
* 除法运算
*/
public class DivideOperation implements Operation {
@Override
public Integer getResult(Integer firstOperateNumber, Integer secondOperateNumber) {
Integer result = firstOperateNumber.intValue() / secondOperateNumber.intValue();
//System.out.println(String.format("%d / %d = %d", firstOperateNumber.intValue(), secondOperateNumber.intValue(), result.intValue()));
return result;
}
}
import com.ant.interview.expression.CalculateEngine;
import org.junit.Test;
public class ExpressionTest {
@Test
public void testExpression() {
String[] expressionArray = new String[] {
"3*0+3+8+9*1",
"3+(3-0)*2"
};
CalculateEngine calculateEngine = new CalculateEngine();
for (String expression : expressionArray) {
int result = calculateEngine.eval(expression);
System.out.println(String.format("%s = %d", expression, result));
}
}
}
思考:
- 为什么要把中缀表达式转化为后缀,前缀?
计算机没法计算带有括号,以及区分优先级的表达式,或者说很难计算。使用后缀,前缀,消除了括号和优先级。 - 中缀表达式如何转化为后缀,前缀表达式?
转化为后缀:从左到右遍历中缀表达式,遇到操作数,输出,遇到操作符,当前操作符的优先级大于栈顶操作符优先级,进栈,否则,弹出栈顶优先级大于等于当前操作符的操作符,当前操作符进栈。
转化为前缀:从右到左遍历中缀表达式,遇到操作数,输出,遇到操作符,当前操作符的优先级大于等于栈顶操作符优先级,进栈,否则,弹出栈顶优先级大于当前操作符的操作符,当前操作符进栈。 - 计算机如何计算后缀,前缀表达式?
计算后缀:从左到右遍历后缀表达式,遇到操作数,放进栈,遇到操作符,栈顶两个数出栈,进行运算,运算结果放进栈,直到读完后缀表达式。
计算前缀:从左到右遍历前缀表达式,遇到操作符,放进栈,遇到操作数,查看栈顶,栈顶为操作符,放进栈,栈顶为操作数,取出栈顶操作数和操作符,进行运算,运算后继续判断栈顶的情况。
参考:
https://www.cnblogs.com/hantalk/p/8734511.html
https://blog.csdn.net/baidu_31497293/article/details/53164395