使用栈计算表达式值

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;
    }
}

猜你喜欢

转载自iamyida.iteye.com/blog/2344309