package stack;
import java.util.Stack;
/**
* Created by Lanxiaowei
* Craated on 2016/12/11 17:29
* 使用栈计算表达式值
*/
public class EvaluateExpression {
public static void main(String[] args) {
String exp = "(1+2+3)*10-2*2-6*2";
int result = calculate(exp);
System.out.println("result:" + result);
}
/**
* 从指定位置开始获取表达式中的操作数
* @param exp 表达式
* @param pos 起始索引位置
* @return
*/
public static String getDigt(String exp,int pos) {
if(!Character.isDigit(exp.charAt(pos))) {
//如果获取到的是左括号,返回提取操作数失败
if(exp.charAt(pos) == '(') {
return "false";
}
throw new IllegalArgumentException("Invalid expression:" + exp);
}
int num = 0;
while(pos < exp.length() && Character.isDigit(exp.charAt(pos))) {
num = num * 10 + exp.charAt(pos++) - '0';
}
return num + "";
}
/**
* 获取指定位置的操作符
* @param exp
* @param pos
* @return
*/
public static char getOper(String exp,int pos) {
switch (exp.charAt(pos)) {
case '+' :
case '-' :
case '*' :
case '/' :
case '(' :
case ')' :
return exp.charAt(pos);
default:
throw new IllegalArgumentException("Invalid expression:" + exp);
}
}
/**
* 获取运算符的优先级
* @param oper
* @return
*/
public static OperatorLevel getOperatorLevel(char oper) {
switch (oper) {
case '+' :
case '-' :
return OperatorLevel.LOW;
case '*' :
case '/' :
return OperatorLevel.HIGH;
default:
throw new IllegalArgumentException("Invalid Operator:" + oper);
}
}
/**
* 计算两个操作数的值
* @param leftNum
* @param oper
* @param rightNum
* @return
*/
public static int opt(int leftNum,char oper,int rightNum) {
int result = 0;
switch (oper) {
case '+' :
result = leftNum + rightNum;
break;
case '-' :
result = leftNum - rightNum;
break;
case '*' :
result = leftNum * rightNum;
break;
case '/' :
//除数为零的情况
if (rightNum == 0) {
throw new IllegalArgumentException("The divisor MUST NOT be zero");
} else {
result = leftNum / rightNum;
}
break;
default:
throw new IllegalArgumentException("Invalid Operator:" + oper);
}
return result;
}
/**
* 比较两个操作符的优先级
* @param oper1 操作符1
* @param oper2 操作符2
* @return
*/
public static boolean isGreater(char oper1,char oper2) {
return getOperatorLevel(oper1).getValue() > getOperatorLevel(oper2).getValue();
}
/**
* 计算表达式求值
* @param exp
* @return
*/
public static int calculate(String exp) {
if(null == exp || "".equals(exp)) {
throw new IllegalArgumentException("Invalid expression:" + exp);
}
exp = exp.replace(" ", "");
exp = "(" + exp + ")";
//操作数栈
Stack<Integer> numStack = new Stack<Integer>();
//操作符栈
Stack<Character> operStack = new Stack<Character>();
int status = 0;
int pos = 0;
Integer tempNum = 0;
char tempOper = '0';
char tempOper2 = '0';
int leftNum = 0;
int rightNum = 0;
String tem = "";
while (pos < exp.length()) {
switch (status) {
case 0: //提取操作数
//如果提取操作数不成功,则进入status=2步骤
tem = getDigt(exp, pos);
if ("false".equals(tem)) {
status = 2;
break;
}
tempNum = Integer.valueOf(tem);
//操作数压栈
numStack.push(tempNum);
//进入步骤1
status = 1;
pos = pos + tem.length();
break;
case 1: //提取操作符
tempOper = getOper(exp,pos);
//如果提取到的是左括号,则抛出异常
if(tempOper == '(') {
throw new IllegalArgumentException("Invalid expression:" + exp);
}
//如果提取到的是右括号,则需要进行计算
if(tempOper == ')') {
while (true) {
//获取栈顶元素
tempOper = operStack.peek();
operStack.pop();
if(tempOper == '(') {
break;
}
rightNum = numStack.pop();
leftNum = numStack.pop();
tempNum = opt(leftNum,tempOper,rightNum);
numStack.push(tempNum);
}
status = 1;
pos++;
} else {
if(operStack.empty()) {
operStack.push(tempOper);
status = 0;
pos++;
} else {
tempOper2 = operStack.peek();
while (tempOper2 != '(' && !isGreater(tempOper,tempOper2)) {
rightNum = numStack.pop();
leftNum = numStack.pop();
tempNum = opt(leftNum,tempOper2,rightNum);
numStack.push(tempNum);
operStack.pop();
if(operStack.empty()) {
break;
}
tempOper2 = operStack.peek();
}
operStack.push(tempOper);
status = 0;
pos++;
}
}
break;
case 2: //提取左括号(
char oper = getOper(exp, pos);
//如果获取到的不是左括号,则提示表达式输入不合法
if (oper != '(') {
throw new IllegalArgumentException("Invalid expression:" + exp);
}
operStack.push(oper);
//进入步骤0提取操作数,因为左括号后面紧跟的必须是操作数
status = 0;
pos++;
break;
}
}
if(numStack.empty()) {
throw new IllegalArgumentException("Invalid expression:" + exp);
}
tempNum = numStack.pop();
if(!numStack.empty()) {
throw new IllegalArgumentException("Invalid expression:" + exp);
}
return tempNum;
}
}