字符串表达式解析计算,支持MAX、MIN多元运算

字符串表达式解析计算,支持MAX、MIN多元运算

前言

近期,由于业务需要,需要对字符串公式进行解析计算,包括加减乘除,幂,取最大最小值运算,同时还包括圆括号的优先级问题。
首先想到的解决思路是,使用栈,将运算符优先级进行排序,计算值按优先级依次入栈,低的在栈底,高的在栈顶。高优先级符号计算完毕后,得到的中间值再次入栈,用于下一个运算符号的计算。符号的优先级计算问题,转为入栈出栈操作。
为实现上述操作,需要将计算优先级混乱的字符串公式,消除括号,按优先级进行排序,后缀式完美贴合了上述操作。

后缀表达式又称逆波兰表达式,明显的特点是:逆波兰表达式中没有括号,计算时将操作符之前的第一个数作为右操作数,第二个数作为左操作数,进行计算,得到的值继续放入逆波兰表达式中。

加(+)、减(-)、乘(*)、除(/)、幂(^),属于二元运算,后缀式可满足,遇到操作符只需取栈顶两个元素进行运算即可。
而最值运算(MAX、MIN),属于多元运算,且要取最值得参数个数不确定,遇到最值运算符时,无法确定从栈顶取多少个元素。为解决上述问题,可以在最值运算符的参数后,再将一个记录参数元素个数的数值入栈。这样遇到最值运算符后,栈弹出的第一个元素标识后续接下来的n个元素都是要取最值的参数元素。

整体解决思路如上,接下来上代码,详情见注释。

接收字符串默认语法正确。关于校验的相关方法,笔者也写过一个拙码,后续分享。

不足可改进之处欢迎指出。

计算类

核心方法:

  • calculate:计算方法,返回计算结果
  • convertToPostfix:转换方法,将字串表达式转换为后缀式,并存入后缀式栈中

注:为区分最值运算符MAX、MIN的括号和优先级圆括号,字符串表达式中MAX、MIN的括号改为方括号 MAX[1,2,3 ],MIN[1,2,3]。

/**
 * 表达式字符串计算工具类
 *
 * @since 2020/11/17 15:59
 * @author MYeshion
 */
public class Calculator {
   
    /** 后缀式栈*/
    private Stack<String> postfixStack = new Stack<>();
    /** 运算符栈*/
    private Stack<String> operatorStack = new Stack<>();
    /** 最大值最小值参数个数栈*/
    private Stack<Integer> paramCountStack = new Stack<>();

    /** 最大最小值前缀*/
    private static final String MAX_MIN_PREFIX = "M";

    /** 最低级运算符*/
    private static final String LOWEST_OPERATOR = ",";

    /** 最值多元运算符*/
    private static final List<String> MULTIMODAL_OPERATOR = Arrays.asList("MIN", "MAX");

    /** 取最大值*/
    private static final String MAX = "MAX";

    /** 取最小值*/
    private static final String MIN = "MIN";

    /** 右方括号*/
    private static final String RIGHT_SQUARE_BRACKET = "]";

    /** 右括号*/
    private static final String RIGHT_BRACKET = ")";

    /** 左括号*/
    private static final String LEFT_BRACKET = "(";

    /**
     * 运算符优先级,越大优先级越高
     */
    private static final Map<String, Integer> OPERATOR_PRECEDENCE = new HashMap<>();

    static {
   
        // 逗号默认最低优先级
        OPERATOR_PRECEDENCE.put(",", -1);
        OPERATOR_PRECEDENCE.put("(", 0);
        OPERATOR_PRECEDENCE.put("[", 0);
        OPERATOR_PRECEDENCE.put("MAX", 1);
        OPERATOR_PRECEDENCE.put("MIN", 1);
        OPERATOR_PRECEDENCE.put("+", 2);
        OPERATOR_PRECEDENCE.put("-", 2);
        OPERATOR_PRECEDENCE.put("*", 3);
        OPERATOR_PRECEDENCE.put("/", 3);
        OPERATOR_PRECEDENCE.put("^", 4);
        OPERATOR_PRECEDENCE.put(")", 5);
        OPERATOR_PRECEDENCE.put("]", 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值