【Java实现】中缀表达式转后缀表达式(用于计算混合四则运算表达式)

一、原理学习

1.什么是中缀表达式?

将运算符写在两个操作数中间的表达式 eg: (6+3*(7-4))-8/2

2.什么是后缀表达式?

将运算符写在操作数之后, 逆波兰式(Reverse Polish notation,RPN,或逆波兰记法),也叫后缀表达式 eg: 6 3 7 4 - * + 8 2 / -

3.中缀表达式 转为 后缀表达式 的步骤

在这里插入图片描述

二、题目

1.要求

要求:
算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间。请设计程序将中缀表达式转换为后缀表达式。

2.输入输出样例

输入样例:
2+3*(7-4)+8/4
输出样例:
[2, 3, 7, 4, -, *, +, 8, 4, /, +]
13.00

3.代码展示部分

package com.xff;

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 CSDNdemo {

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

        char[] chars = reader.readLine().replaceAll(" ", "").toCharArray();
    	//char[] chars = "2+3*(7-4)+8/4".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 == '.';

    }
}


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

HAL9000pp

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

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

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

打赏作者

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

抵扣说明:

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

余额充值