中缀表达式转后缀表达式求值(java实现,带括号可以是正负小数)

中缀表达式转后缀表达式求值(java实现,可以是正负小数)

步骤:

  1. 初始化一个栈和一个队列,一个StringBuilder字符串sb:运算符栈op,存储中间结果的队列exp,存储数字的字符串sb。
  2. 从左到右扫描中缀表达式。
  3. 遇到操作数时,将其添加到exp(一位数)。
    1. (多位数的情况)扫描到:第一个字符(不是左括号)或数字或小数点.直接加入到sb中(因为第一位要么是±、(,要么是数字)
    2. 判断这个数字是否结束了,结束就将sb转化为字符串加入到exp队列中。
      1. 如果扫描到的这个数字的后一位是操作符或括号( +,-,*,/,(,) )这个数字就结束了
      2. 如果所描到的这个数字是最后一位,也结束了。
  4. 遇到运算符时,比较其与op栈顶运算符的优先级。
    1. 如果op为空,则直接入栈。
    2. 否则,若优先级比栈顶运算符的高,也将运算符压入op。
    3. 否则,将op栈顶的运算符弹出并添加到exp中,再次重复遇到运算符的操作(4)。
  5. 遇到括号时:
    1. 如果是"(",直接压入op。
    2. 如果是")",则依次弹出op栈顶的运算符,并压入exp,直到遇到"("为止,此时将这一对括号丢掉。
  6. 重复步骤2到5,直到表达式的最右边。
  7. 将op中剩余的运算符依次弹出并添加到exp中。

exp即为后缀表达式。后缀表达式的计算很简单,就不描述了。

以下是java代码实现。可以实现正负小数,带括号。
测试的样例:
第二行是List输出的后缀表达式
第三行是结果(保留2位小数,四舍五入)
如果输入的表达式正确的情况下:的在正负小数,带括号上有bug可以评论告诉我,(本人菜鸡一枚)。
测试的样例

package pers.calculator;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 输入一个 中缀表达式 转化为 后缀表达式 然后求值
 */
public class NifToSufAndCalc {

    public static void main(String[] args) throws Exception {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        char[] chars = reader.readLine().replaceAll(" ", "").toCharArray();
        // 获得后缀表达式
        List<String> suffixList = nifToSuf(chars);
        System.out.println(suffixList);
        // 计算后缀表达式
        BigDecimal res = calcSuffixExpression(suffixList);
        System.out.println(res.setScale(2, RoundingMode.HALF_UP));
    }

    /**
     * 中缀表达式转化为后缀表达式
     *
     * @param chars 中缀表达式
     * @return 返回后缀表达式
     */
    public static List<String> nifToSuf(char[] chars) {
        List<String> exp = new ArrayList<>();
        Stack<Character> op = new Stack<>();
        StringBuilder sb = new StringBuilder("");
        for (int i = 0; i < chars.length; i++) {

            // 如果是数字
            if ((i == 0 && chars[i] != '(') || (i != 0 && isDigit(chars[i], chars[i - 1]))) {
                sb.append(chars[i]);
                // 如果是最后一位 或者下一位是字符,数字添加到exp队列,sb清空
                if (i == chars.length - 1 || (i + 1 < chars.length && isSymbol(chars[i + 1]))) {

                    exp.add(sb.toString());
                    sb = new StringBuilder("");
                }
                // 如果是括号
            } else if (isBracket(chars[i])) {
                // 如果是左括号 直接入op栈
                if (chars[i] == '(') {
                    op.push(chars[i]);
                } else {
                    // 右括号
                    // 将op栈出栈 添加到exp直到遇到'(',将这一对 '(' ')' 舍去
                    char temp;
                    while ((temp = op.pop()) != '(') {
                        exp.add(temp + "");
                    }
                }
                // 如果是操作符
            } else if (isOperation(chars[i])) {
                while (true) {
                    // 空的栈直接入栈
                    if (op.isEmpty()) {
                        op.push(chars[i]);
                        break;
                        // 如果栈顶的符号优先级小于 扫描到的符号 入栈
                    } else if (getPriority(op.peek()) < getPriority(chars[i])) {
                        op.push(chars[i]);
                        break;
                        // 栈顶的符号优先级大于等于 扫描到的符号 出栈给exp,并继续扫描栈顶下一个符号
                    } else {
                        exp.add(op.pop() + "");
                    }
                }

            }
        }
        // 将剩余的符号全部入exp
        while (!op.isEmpty()) {
            exp.add(op.pop() + "");
        }

        return exp;
    }

    /**
     * 计算后缀表达式
     *
     * @param suffixExp 输入后缀表达式
     * @return @code{BigDecimal}
     */
    public static BigDecimal calcSuffixExpression(List<String> suffixExp) {
        Stack<BigDecimal> numStack = new Stack<>();
        for (String str : suffixExp) {
            // 如果是操作符
            if (str.length() == 1 && isOperation(str.charAt(0))) {
                BigDecimal num2 = numStack.pop();
                BigDecimal num1 = numStack.pop();
                numStack.push(calcValueOfTwoNum(num1, num2, str));

            } else {
                numStack.push(new BigDecimal(str));
            }
        }
        return numStack.peek();
    }

    public static BigDecimal calcValueOfTwoNum(BigDecimal num1, BigDecimal num2, String op) {
        switch (op) {
            case "+":
                return num1.add(num2);
            case "-":
                return num1.subtract(num2);
            case "*":
                return num1.multiply(num2);
            case "/":
                if (num2.signum() == 0) {
                    throw new RuntimeException("除数不能为0");
                }
                // 除法保留2位小数,四舍五入
                return num1.divide(num2, 2, RoundingMode.HALF_UP);
        }
        throw new RuntimeException("没有此操作符");
    }

    // 获取优先级
    public static int getPriority(char ch) {
        switch (ch) {
            case '(':
                return 0;
            case '+':
            case '-':
                return 1;
            case '*':
            case '/':
                return 2;
        }
        throw new RuntimeException("不是加减乘除或者(");
    }

    public static boolean isSymbol(char ch) {
        return isOperation(ch) || isBracket(ch);
    }

    public static boolean isOperation(char ch) {
        return ch == '+' || ch == '-' || ch == '*' || ch == '/';
    }

    public static boolean isBracket(char ch) {
        return ch == '(' || ch == ')';
    }

    public static boolean isDigit(char ch, char leftBracket) {
        // 如果前一个是左括号 右边的数字可能带有正负号
        if (leftBracket == '(') {
            return ch == '-' || ch == '+' || (ch >= 48 && ch <= 57);
        }
        // 前一个符号不是左括号只能是数字或小数点
        return (ch >= 48 && ch <= 57) || ch == '.';

    }
}

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值