【面试题-J2SE-栈】计算表达式的计算

计算表达式的计算

import org.junit.Test;

import java.util.Arrays;
import java.util.Stack;

/**
 * 计算表达式的计算
 * Created by Relish on 2016/8/14.
 */
public class CalculateUtil {//Infix:中缀;Postfix:后缀

    @Test
    public void test() {
        String exp = "10+2*3/(4-5.0)";
        System.out.println(calculate(exp));
    }


    private static final String REGEX_NUM = "[0-9]+|([0-9]+\\.[0-9]+)";

    private static int[] value = new int[50];

    static {
        //各个运算符的优先级(越大越优先)
        value['+'] = 0;
        value['-'] = 0;
        value['*'] = 1;
        value['/'] = 1;
        value['('] = 2;
        value[')'] = -1;
    }

    public String calculate(String rawExp) {
        String[] postfixExp = infix2Postfix(rawExp);
        //TODO 测试
        System.out.println("后缀:" + Arrays.toString(postfixExp));

        Stack<String> numStack = new Stack<>();
        for (String s : postfixExp) {
            if (s.matches(REGEX_NUM)) {
                numStack.push(s);
            } else {
                if (numStack.size() == 1) {
                    return numStack.pop();
                }
                double n2 = Double.parseDouble(numStack.pop());
                double n1 = Double.parseDouble(numStack.pop());
                switch (s.charAt(0)) {
                    case '+':
                        numStack.push((n1 + n2) + "");
                        break;
                    case '-':
                        numStack.push((n1 - n2) + "");
                        break;
                    case '*':
                        numStack.push((n1 * n2) + "");
                        break;
                    case '/':
                        if (n2 == 0) {
                            System.err.println("除数不能为0!");
                            return null;
                        }
                        numStack.push((n1 / n2) + "");
                        break;
                }
            }
        }
        return numStack.pop();
    }

    /**
     * 中缀转后缀
     *
     * @param rawExp 中缀表达式
     * @return 后缀表达式
     */
    private static String[] infix2Postfix(String rawExp) {
        if (!isExpressionLegitimate(rawExp)) {
            System.err.println("非法计算表达式!");
            return null;
        }
        Stack<Character> opStack = new Stack<>();
        String[] splitExp = split(rawExp);//数字、运算符(包含左右扩号)切割
        //TODO 测试
        System.out.println("切割:" + Arrays.toString(splitExp).replaceAll("[\\[\\]]", "").replace(", ", " "));

        Stack<String> postfixStack = new Stack<>();
        for (String s : splitExp) {
            if (s.matches(REGEX_NUM)) {
                postfixStack.push(s);
            } else if (s.length() == 1 && isCharacterLegitimate(s.charAt(0))) {
                char op = s.charAt(0);//+、-、*、/、(、)
                if (opStack.isEmpty()) {
                    opStack.push(op);
                } else {
                    if (isSimpleOperator(op) || op == '(') {//+、-、*、/、(
                        if (value[op] > value[opStack.peek()] || op == '(') {
                            opStack.push(op);
                        } else {
                            while ((!opStack.isEmpty()) && value[op] <= value[opStack.peek()]) {
                                char c = opStack.peek();
                                if (c == '(') {
                                    break;
                                } else {
                                    postfixStack.push(opStack.pop() + "");
                                }
                            }
                            opStack.push(op);
                        }
                    } else {//)右括号
                        while ((!opStack.isEmpty())) {
                            char c = opStack.peek();
                            if (c == '(') {
                                opStack.pop();
                                break;
                            } else {
                                postfixStack.push(c + "");
                                opStack.pop();
                            }
                        }
                    }
                }
            }
        }
        while (!opStack.isEmpty()) {
            postfixStack.push(opStack.pop() + "");
        }
        String[] postfix = new String[postfixStack.size()];
        int i = postfix.length;
        while (!postfixStack.isEmpty()) {
            postfix[--i] = postfixStack.pop();
        }
        return postfix;
    }

    /**
     * 将运算符(包含左右括号)、数字分割成字符串数组
     *
     * @param rawExp 计算表达式
     * @return 字符串数组
     */
    private static String[] split(String rawExp) {
        StringBuilder sb = new StringBuilder();
        for (char c : rawExp.toCharArray()) {
            if (isCharacterLegitimate(c)) {
                sb.append(",");
                sb.append(c);
                sb.append(",");
            } else {
                sb.append(c);
            }
        }
        return sb.toString().replaceAll(",{2}", ",").split(",");
    }

    /**
     * 括号是否匹配
     *
     * @param exp 计算表达式
     * @return 匹配与否
     */
    private static boolean isBracketsMatching(String exp) {
        Stack<Character> stack = new Stack<>();
        for (char c : exp.toCharArray()) {
            if (c == '(') {
                stack.push(c);
            } else if (c == ')') {
                if (stack.peek() == '(') {
                    stack.pop();
                } else {
                    return false;
                }
            }
        }
        return stack.isEmpty();
    }

    /**
     * 计算法表达式是否合法
     *
     * @param exp 计算表达式
     * @return 合法与否
     */
    private static boolean isExpressionLegitimate(String exp) {
        if (exp.contains("(") && exp.contains(")") && isBracketsMatching(exp)) {
            int start = exp.indexOf("(");
            int end = exp.lastIndexOf(")");
            return isExpressionLegitimate(exp.substring(start + 1, end)) &&
                    isExpressionLegitimate(exp.substring(0, start) + "0" +
                            (end + 1 >= exp.length() ? "" : exp.substring(end + 1)));
        } else {
            return exp.matches("^([0-9]+|([0-9]+\\.[0-9]+))([+\\-*/]([0-9]+|([0-9]+\\.[0-9]+)))*$");
        }
    }

    /**
     * 是否是+、-、*、/中的任何一个字符
     *
     * @param ch 字符
     * @return 匹配与否
     */
    private static boolean isSimpleOperator(char ch) {
        return ch == '+' || ch == '-' || ch == '*' || ch == '/';
    }

    /**
     * 是否是合法字符:+、-、*、/、(、)
     *
     * @param ch 字符
     * @return 合法与否
     */
    private static boolean isCharacterLegitimate(char ch) {
        return ch == '(' || ch == ')' || isSimpleOperator(ch);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值