[JDK17]逆波兰计算器的简单实现(含一般表达式转逆波兰表达式)

本文介绍了如何使用Java编程实现一个工具类,将中缀表达式转换为后缀表达式,以及一个逆波兰表达式计算器,用于计算后缀表达式的计算结果。通过优先级规则处理运算符和括号,确保表达式的正确计算。
摘要由CSDN通过智能技术生成
将中缀表达式转成后缀表达式的工具类:
package Stack.PoLandCaculation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Stack;

/**
 * 将中缀表达式转成后缀表达式的工具类
 */
public class PoLandTransform {

    /**
     * 一般表达式转后缀表达式
     * @param commonExpression 一般表达式
     * @return 返回后缀表达式字符串数组,数组每一个元素都是一个数或者运算符
     */
    public static ArrayList<String> toPostfixExpression(String commonExpression){
        ArrayList<String> list = PoLandTransform.toStringArray(commonExpression);
        Stack<String> s1 = new Stack<>();
        Stack<String> s2 = new Stack<>();

        for (int i = 0; i < list.size(); i++) {//当遍历到数字时,直接压入s2栈
            String str = list.get(i);
            if (str.matches("\\d+(\\.\\d+)?")) {
                s2.push(str);
            } else {
                //遍历到运算符
                //s1为空 或者 遍历到'(' 或者 s1栈顶是'(',运算符直接压入s1栈
                if (s1.isEmpty() || str.equals("(") || s1.peek().equals("(")) {
                    s1.push(str);
                } else if (str.equals(")")) {
                    //当遍历到')'时
                    //弹出s1中的运算符并压入到s2,直到s1栈顶是'('。最后弹出s1栈顶的'('
                    while (!s1.peek().equals("(")) s2.push(s1.pop());
                    s1.pop();
                } else {
                    //当遍历到加减乘除这四个运算符
                    //先计算当前运算符与s1栈顶运算符的优先级
                    int priority = PoLandTransform.priority(str, s1.peek());

                    if (priority == 1) {
                        //当前运算符比栈顶运算符优先级高
                        //直接压入s1栈
                        s1.push(str);
                    } else {
                        //比s1栈顶优先级低
                        //弹出一个s1元素并压入s2,然后当前运算符再次与弹出一次后的s1栈顶元素对比
                        s2.push(s1.pop());
                        //回滚索引
                        i--;
                    }
                }
            }
        }
        //s1栈剩余的运算符依次弹入s2栈中
        while (!s1.isEmpty()) s2.push(s1.pop());

        //s2栈依次弹出,添加到新的list中
        ArrayList<String> newList = new ArrayList<>();
        while (!s2.isEmpty()) newList.add(s2.pop());

        //将list转置后返回
        Collections.reverse(newList);
        return newList;

    }

    /**
     * 识别算术表达式,并返回处理好的算式列表
     * @param expression 算术表达式
     * @return 返回处理好的表达式列表
     */
    private static ArrayList<String> toStringArray(String expression){
        //表达式匹配到非法字符(匹配到加减乘除和数字以及小数点以外的字符)
        if (expression.replaceAll(" ","").matches("[^\\d\\+\\-\\*\\/\\.]")){
            throw new RuntimeException("表达式存在非法字符!");
        }
        ArrayList<String> list = new ArrayList<>();
        //将表达式转char数组方便后续处理
        char[] exp = expression.replaceAll(" ","").toCharArray();
        //定义numStr方便后续拼接多位数数字
        String numStr = "";
        for (int i = 0; i < exp.length; i++) {
            if (exp[i] >= '0' && exp[i] <= '9' || exp[i] == '.'){
                //遍历到数字或者小数点,都拼接到numStr
                numStr += exp[i];
                if (i == exp.length - 1){
                    //遍历到最后一个数字,记得把最后一个数字也添加到列表list
                    list.add(numStr);
                }
            }else if(exp[i] == '+' || exp[i] == '-' || exp[i] == '*' || exp[i] == '/' || exp[i] == '(' || exp[i] == ')'){
                //遍历到运算符,先把拼接好的numStr添加进list,然后重置numStr
                if (!numStr.isEmpty()) list.add(numStr);
                numStr = "";

                //把运算符也添加进list
                list.add(""+exp[i]);
            }
        }
        return list;
    }

    /**
     * 计算运算符优先级
     * @param cur 当前运算符
     * @param stackEle 栈顶运算符
     * @return 返回0代表当前运算符优先级低或者相等,返回1代表当前运算符优先级高
     */
    private static int priority(String cur,String stackEle){
        if (stackEle.equals("*") || stackEle.equals("/")){
            return (cur.equals("+") || cur.equals("-")) ? 0 : 1;
        }
        return (cur.equals("+") || cur.equals("-")) ? 0 : 1;
    }
}

逆波兰计算器:

package Stack.PoLandCaculation;

import java.util.ArrayList;
import java.util.Stack;

/**
 * 逆波兰表达式计算器
 */
public class PoLandCaculation {

    /**
     * 将一般算式转换成逆波兰表达式后返回算式计算结果
     * @param expression 一般算式
     * @return 返回计算结果
     */
    public static Double poLandCaculate(String expression){
        //获取后缀表达式
        ArrayList<String> postfixList = PoLandTransform.toPostfixExpression(expression);
        Stack<Double> stack =new Stack<>();
        postfixList.forEach(str ->{
            //遍历到数字直接入栈
            if (str.matches("\\d+(\\.\\d+)?")){
                stack.push(Double.parseDouble(str));
            }else {
                //遍历到运算符
                //栈顶弹出两个元素,与当前运算符计算后重新入栈
                try {
                    Double result = PoLandCaculation.calculate(stack.pop(), stack.pop(), str);
                    stack.push(result);
                }catch (ArithmeticException e){
                    throw new ArithmeticException("出现算术异常!");
                }catch (RuntimeException e){
                    throw new RuntimeException(e.getMessage());
                }
            }
        });
        //栈中最后剩下的元素就是计算结果,返回结果
        return stack.pop();
    }

    /**
     * 根据运算符进行计算并返回结果
     * @param num1
     * @param num2
     * @param operator
     * @return
     * @throws RuntimeException
     */
    private static Double calculate(Double num1,Double num2,String operator) throws RuntimeException{
        return switch (operator){
            case "+"-> num2+num1;
            case "-"-> num2-num1;
            case "*"-> num2*num1;
            case "/"-> num2/num1;
            default -> throw new RuntimeException("未知异常");
        };
    }
}

测试代码:

package Stack.PoLandCaculation;

import java.util.Scanner;

public class PoLandCaculationTest {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        while (true) {
            System.out.println("--------------------------------------------------------------------------------------");
            System.out.println("[输入e退出程序]");
            System.out.println("请输入计算表达式(支持小数运算、多位数运算、小括号运算):");
            System.out.println("--------------------------------------------------------------------------------------");

            String expression = scan.next();
            if (expression.equalsIgnoreCase("e")) return;
            Long startTime = System.currentTimeMillis();

            Double result = null;
            try {
                result = PoLandCaculation.poLandCaculate(expression);
            } catch (ArithmeticException e) {
                System.out.println(e.getMessage());
            }catch (Exception e){
                e.printStackTrace();
            }
            Long endTime = System.currentTimeMillis();
            System.out.println("计算结果为:["+result+"]");
            System.out.println("本次计算用时:"+ (endTime-startTime) +" ms");
        }
    }
}

测试图:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值