波兰表达式、逆波兰表达式、判断是否是合法算术表达式、计算器的实现--Java

public class Calculator {
    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        while (true) {
            // 输入一个算数表达式
            System.out.println("please enter expression : ");
            String expression = in.nextLine();

            // 调用bracketToCircle()方法将其他括号转换成圆括号的表达式
            String exprAfterTransfer = expressionToComputerOperators(expression);

//            System.out.println("原表达式" + expression);
//            System.out.println("转换后表" + exprAfterTransfer);

            // isTrueExpression(expression)  判断是否是一个合格的算数表达式
            boolean trueExpression = isTrueExpression(exprAfterTransfer);
            if (trueExpression) {
                List list = addToList(exprAfterTransfer);
//                List preExpression = getPreExpression(list);
//                double result = getResultByUsePreExpression(preExpression);
//                System.out.println(expression + " = " + result);

                List postExpression = getPostExpression(list);
                double result = getResultByUsePostExpression(postExpression);
                System.out.println(expression + " = " + result);
            } else {
                System.err.println("{ " + expression + " } is error math expression!");
            }
        }
    }

    // 使用后缀表达式得到算术表达式的值
    public static double getResultByUsePostExpression(List<String> list) {
        Stack<String> stack = new Stack<>();
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).matches("\\d+\\.{0,1}\\d*")) {
                stack.push(list.get(i));
            } else {
                double num1 = Double.parseDouble(stack.pop());
                double num2 = Double.parseDouble(stack.pop());
                double result = 0;
                switch (list.get(i)) {
                    case "+":
                        result = num2 + num1;
                        break;
                    case "-":
                        result = num2 - num1;
                        break;
                    case "*":
                        result = num2 * num1;
                        break;
                    case "/":
                        result = num2 / num1;
                        break;
                }
                stack.push("" + result);
            }
        }
        return Double.parseDouble(stack.pop());
    }


    // 中缀表达式得到后缀表达式
    public static List getPostExpression(List<String> list) {
        Stack<String> operators = new Stack<>();
        Stack<String> median = new Stack<>();
        List<String> list1 = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            while (true) {
                if (list.get(i).matches("\\d+\\.{0,1}\\d*")) {
                    median.push(list.get(i));
                    break;
                } else if (isOperator(list.get(i).charAt(0))) {
                    if (operators.empty() || operators.peek().equals("(")) {
                        operators.push(list.get(i));
                        break;
                    } else if (getPriority(list.get(i)) > getPriority(operators.peek())) {
                        operators.push(list.get(i));
                        break;
                    } else {
                        median.push(operators.pop());
                    }
                } else if (isBracket(list.get(i).charAt(0))) {
                    if (list.get(i).equals("(")) {
                        operators.push(list.get(i));
                        break;
                    } else {
                        while (!operators.empty() && !operators.peek().equals("(")) {
                            median.push(operators.pop());
                        }
                        if (!operators.empty()) {
                            operators.pop();
                        }
                        break;
                    }
                }
            }
        }
        while (!operators.empty()) {
            median.push(operators.pop());
        }
        while (!median.empty()) {
            list1.add(median.pop());
        }
        Collections.reverse(list1);
        return list1;
    }

    // 如果 * / 优先级最高为2  +-为1 其他为0
    public static int getPriority(String str) {
        if (str.equals("+") || str.equals("-")) {
            return 1;
        } else if (str.equals("*") || str.equals("/")) {
            return 2;
        } else {
            return 0;
        }
    }

    // 使用前缀表达式计算算术表达式的算数值
    public static double getResultByUsePreExpression(List<String> list) {
        Stack<String> stack = new Stack<>();
        for (int i = list.size() - 1; i >= 0; i--) {
            if (list.get(i).matches("\\d+\\.{0,1}\\d*")) {
                stack.push(list.get(i));
            } else {
                if (isOperator(list.get(i).charAt(0))) {
                    double num1 = Double.parseDouble(stack.pop());
                    double num2 = Double.parseDouble(stack.pop());
                    double result = 0;
                    switch (list.get(i)) {
                        case "+":
                            result = num1 + num2;
                            break;
                        case "-":
                            result = num1 - num2;
                            break;
                        case "*":
                            result = num1 * num2;
                            break;
                        case "/":
                            result = num1 / num2;
                            break;
                    }
                    stack.push("" + result);
                }
            }
        }
        return Double.parseDouble(stack.pop());
    }

    // 转化为前缀表达式

    /**
     * (1) 初始化两个栈:运算符栈S1和储存中间结果的栈S2;
     * (2) 从右至左扫描中缀表达式;
     * (3) 遇到操作数时,将其压入S2;
     * (4) 遇到运算符时,比较其与S1栈顶运算符的优先级:
     * (4-1) 如果S1为空,或栈顶运算符为右括号“)”,则直接将此运算符入栈;
     * (4-2) 否则,若优先级比栈顶运算符的较高或相等,也将运算符压入S1;
     * (4-3) 否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;
     * (5) 遇到括号时:
     * (5-1) 如果是右括号“)”,则直接压入S1;
     * (5-2) 如果是左括号“(”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到右括号为止,此时将这一对括号丢弃;
     * (6) 重复步骤(2)至(5),直到表达式的最左边;
     * (7) 将S1中剩余的运算符依次弹出并压入S2;
     * (8) 依次弹出S2中的元素并输出,结果即为中缀表达式对应的前缀表达式
     **/
    public static List getPreExpression(List<String> list) {
        List<String> list1 = new ArrayList<>();
        Stack<String> operators = new Stack<>();
        Stack<String> median = new Stack<>();
        for (int i = list.size() - 1; i >= 0; i--) {
            String value = list.get(i);
            while (true) {
                if (value.matches("\\d+\\.{0,1}\\d*")) {
                    median.push(value);
                    break;
                } else if (isOperator(value.charAt(0))) {
                    if (operators.empty() || operators.peek().equals(")")) {
                        operators.push(value);
                        break;
                    } else if (getPriority(value) >= getPriority(operators.peek())) {
                        operators.push(value);
                        break;
                    } else {
                        median.push(operators.pop());
                    }
                } else if (isBracket(value.charAt(0))) {
                    if (value.equals(")")) {
                        operators.push(value);
                        break;
                    } else {
                        while (!operators.empty() && !operators.peek().equals(")")) {
                            median.push(operators.pop());
                        }
                        if (!operators.empty() && operators.peek().equals(")")) {
                            operators.pop();
                        }
                        break;
                    }
                }
            }
        }
        while (!operators.empty()) {
            median.push(operators.pop());
        }
        while (!median.empty()) {
            list1.add(median.pop());
        }
        return list1;
    }

    // 将表达式的数字、运算符、括号...... 添加到List中,方便操作
    public static List addToList(String expression) {
        List<String> list = new ArrayList<>();
        int i = 0;
        do {
            char ch = expression.charAt(i);
            String str = "";
            if (ch == ' ') {
                i++;
            } else {
                if (isOperator(ch) || isBracket(ch)) {
                    list.add(str += ch);
                    i++;
                } else if (isNumber(ch)) {
                    str += ch;
                    i++;
                    while (i < expression.length() && (isNumber(expression.charAt(i)) || isPoint(expression.charAt(i)))) {
                        str += expression.charAt(i);
                        i++;
                    }
                    list.add(str);
                }
            }
        } while (i < expression.length());
        return list;
    }

    // 获取后一个有效字符下标
    public static int getPreIndexOfNotBlankSpace(String expression, int i) {
        // 如果下表是最后一个字符下标那么就返回最后一个字符下标
        if (i == 0) {
            return 0;
        } else if (i < 0 || i >= expression.length()) {
            throw new RuntimeException("error");
        } else {
            i--;
            while (expression.charAt(i) == ' ') {
                i--;
            }
            return i;
        }
    }

    // 获取前一个有效字符的下标
    public static int getNextIndexOfNotBlankSpace(String expression, int i) {
        // 如果下标为0 那么前一个有效字符就是0
        if (i == expression.length() - 1) {
            return expression.length() - 1;
        } else if (i < 0 || i >= expression.length()) {
            throw new RuntimeException("error");
        } else {
            i++;
            while (expression.charAt(i) == ' ') {
                i++;
            }
            return i;
        }
    }

    // 判断是否是合法算术表达式
    public static boolean isTrueExpression(String expression) {
        // 如果一开始就是点(.)肯定就不是合法的表达式  合法的算术表达式含有数字、小数点、括号、运算符
        if ("".equals(expression) || isOperator(expression.charAt(0)) || isOperator(expression.charAt(expression.length() - 1)) || isPoint(expression.charAt(0)) || isPoint(expression.charAt(expression.length() - 1))) {
            return false;
        } else {

            // 控制括号成对
            Stack<Character> stack = new Stack<>();

            // 循环判断表达式的每一个字符是符合法
            int i = 0;
            while (i < expression.length()) {
                char ch = expression.charAt(i);
                // 如果此字符不是数字、运算符、小数点、括号、空格(习惯分开 比如:2 + 4) 那么就是不合法
                if (isNumber(ch) || isOperator(ch) || isPoint(ch) || isBracket(ch) || ch == ' ') {
                    //如果此字符是空格  那么如果他的前一个或后一个是小数点、前后都是数字或者元素字符,那么这个表达式就是不合法

                    // 次字符前后可能有多个空格,调用方法得到此字符的前/后一个的有效字符
                    int pre = getPreIndexOfNotBlankSpace(expression, i);
                    int next = getNextIndexOfNotBlankSpace(expression, i);
//                    System.out.println(pre + " " + next);
                    if (ch == ' ') {
                        if (isPoint(expression.charAt(pre)) || isPoint(expression.charAt(next)) || (isNumber(expression.charAt(pre))) && isNumber(expression.charAt(next)) || (isOperator(expression.charAt(pre))) && isOperator(expression.charAt(next))) {
                            return false;
                        }
                    }

                    // 如果是左括号( 那么下一个有效字符必须是左括号或者数字
                    if (ch == '(') {
                        if (isPoint(expression.charAt(next)) || expression.charAt(next) == '*' || expression.charAt(next) == '/' || expression.charAt(next) == ')') {
                            return false;
                        }
                        // 入栈
                        stack.push(ch);
                    }
                    // 如果是) 如果栈空则说明不合法 否则弹出一个(   )后面只可以是运算符或者)
                    if (ch == ')') {
                        if (stack.empty() || (!isOperator(expression.charAt(next)) && expression.charAt(next) != ')')) {
                            return false;
                        } else {
                            stack.pop();
                        }
                    }

                    // 如果是除号 后一个数是0就不合法 除数不能是0
                    if (ch == '/') {
                        if (expression.charAt(next) == '0') {
                            return false;
                        }
                    }

                    // 如果是运算符,前一个或后一个不能是小数点、操作符
                    if (isOperator(ch)) {
                        if (isPoint(expression.charAt(pre)) || isPoint(expression.charAt(next)) || expression.charAt(next) == ')' || isOperator(expression.charAt(next))) {
                            return false;
                        }
                    }

                    // 如果是小数点前后都必须是数字
                    if (isPoint(ch)) {
                        if (!isNumber(expression.charAt(pre)) || !isNumber(expression.charAt(next))) {
                            return false;
                        }
                    }
                    i++;
                } else {
                    return false;
                }
            }

            // 如果字符都合法最后判断括号是否成对
        }
        return true;
    }

    // 将从控制台得到的表达式的某些字符转化为计算机能识别的字符
    public static String expressionToComputerOperators(String expression) {
        // 将输入的算术表达式的[]{}转化为圆括号()   因为常用的括号为() 顺便去除首尾空格  × --> *  ÷ --> /
        expression = expression.trim();
        String str = "";
        for (int i = 0; i < expression.length(); i++) {
            char ch = expression.charAt(i);
            if (ch == '[' || ch == '{') {
                str += "(";
            } else if (ch == ']' || ch == '}') {
                str += ")";
            } else if (ch == '×') {
                str += '*';
            } else if (ch == '÷') {
                str += "/";
            } else {
                str += ch;
            }
        }
        return str;
    }

    // 判断这个字符是不是数字
    public static boolean isNumber(char ch) {
        if (ch >= '0' && ch <= '9') {
            return true;
        } else {
            return false;
        }
    }

    // 判断这个字符是不是运算符
    public static boolean isOperator(char ch) {
        if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
            return true;
        } else {
            return false;
        }
    }

    // 判断这个字符是不是小数点
    public static boolean isPoint(char ch) {
        return ch == '.';
    }

    // 判断这个字符是不是括号
    public static boolean isBracket(char ch) {
        return ch == '(' || ch == ')';
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MC6058

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值