(算法)java完成解析数学算式(计算器)二 —— 用数组解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37969433/article/details/81189195

一、程序要求

解析一般数学算式,实现简单的带括号的加减乘除运算。

二、基本思路

上一篇我以正常思考计算式子的角度考虑,介绍了直接递归遍历字符串解析数学四则运算式子,思路很好理解,但程序写出来较为难读。这里再用另一种方法,采用java的ArrayList集合(数组)来实现目的。

这次我从易到难考虑:

  • 1)、单个数:如3,运算结果即这个数
  • 2)、加入加减后运算:如1+6-4,从左往右依次加减,式子将变为1)
  • 3)、加入乘除后运算:如1+2*3-4,从左往右依次先做乘除,式子将会变为2)
  • 4)、加入括号后运算:如1*(1+2*3-4)+5,单独拿出括号中的内容,即3),将计算结果替换括号1*3+5,又变成3)的情况

因此,对于一个数字式子,我们应该考虑化繁为简、由难变易。往往加入括号后,让我们解析起来增加了困难,所以,解析无括号的四则运算是我们应该考虑的第一步。

对于一个无括号的数字式子:-1+2*-3/3+-2 :
  • 1、把数字和运算符分离,分别放入两个数组:
    这里写图片描述
  • 2、遍历符号数组,先从左向右找乘除,如上b1为第一个乘除号,则删除b1、a1、a2,将a1 b1 a2的运算结果插入到a1;以此类推至无乘除号:
    这里写图片描述
  • 3、同2,从左往右依次计算加减至无加减:
    这里写图片描述
  • 4、此时a0即为运算结果
对于一个有括号的式子,我们只有按无括号的计算方法计算出括号中的值,从里到外将括号替换为计算结果即可,再进一步化简为整个的无括号的式子!

三、代码

环境:

  • Eclipse Java EE IDE(Version: Oxygen.1a Release (4.7.1a))
  • jdk1.8.0_131

先写一个最基本的两位数四则运算方法,比较简单,没有写注释:

public static double doubleCal(double a1, double a2, char operator) throws Exception {
        switch (operator) {
        case '+':
            return a1 + a2;
        case '-':
            return a1 - a2;
        case '*':
            return a1 * a2;
        case '/':
            return a1 / a2;
        default:
            break;
        }
        throw new Exception("illegal operator!");
    }

计算无括号的四则运算:

private static String noBrackets(String expr) throws Exception {
        //这个正则是匹配是不是符合无括号表达式的规则,即      数字+运算符+数字+运算符....
        if (!expr.matches("-?\\d+(\\.\\d+)?([+\\-*/]-?\\d+(\\.\\d+)?)*")) {
            throw new Exception("Wrong format!");
        }
        System.out.println("计算:"+expr);
        /* 盛放运算数 */
        List<Double> number = new ArrayList<Double>();
        /* 盛放运算符 */
        List<Character> operator = new ArrayList<Character>();

        /* 将expr打散分散到运算数和运算符数组 */
        //这个正则为匹配表达式中的数字
        Pattern p = Pattern.compile("(?<!\\d)-?\\d+(\\.\\d+)?");
        Matcher m = p.matcher(expr);
        while (m.find()) {
            number.add(Double.valueOf(m.group()));//将该数字放进数字的数组
            if (m.end() < expr.length()) {
                operator.add(expr.charAt(m.end()));//与该数字相邻的运算符放入运算符的数组
            }
        }
        System.out.println("计算数数组:" + number);
        System.out.println("计算符数组:" + operator);

        /*
         * 先算乘除,再算加减 这里利用了逻辑或||的运算法则,正好对应计算式子的乘除加减的顺序
         */
        int i = -1;
        while (-1 != (i = operator.indexOf('*')) || -1 != (i = operator.indexOf('/'))
                || -1 != (i = operator.indexOf('+')) || -1 != (i = operator.indexOf('-'))) {
            char c = operator.get(i);
            operator.remove(i);
            double a1 = number.remove(i);
            double a2 = number.remove(i);
            number.add(i, doubleCal(a1, a2, c));
        }
        String res = number.get(0)+"";
        System.out.println("此步结果:"+res);
        return res;

    }

计算带括号的四则运算:

public static String getResult(String expr) throws Exception {
        System.out.println("开始计算:"+expr);
        /*表示最后一个左括号*/
        int lIndex = -1;
        /*与该左括号对应的右括号*/
        int rIndex = -1;
        /*去括号*/
        while(-1 != (lIndex = expr.lastIndexOf("("))) {
            rIndex = expr.indexOf(")",lIndex);
            expr = expr.substring(0,lIndex)+noBrackets(expr.substring(lIndex+1, rIndex))+expr.substring(rIndex+1);
        }
        /*计算结果*/
        return noBrackets(expr);
    }

测试方法:

public static void main(String[] args) throws Exception {
        String str = "-3.5*(4.5-(4+(-1-1/2)))";
        System.out.println(getResult(str));
    }

四、运行结果

这里写图片描述

五、分析

这种方法整体思路和第一种差不多,理解算法后程序更易于读懂,但对数组需要多次遍历和移位,效率上仍不是很高。为了进一步优化,换一种数据结构“栈”来存取数据可以达到更好的执行效果。

猜你喜欢

转载自blog.csdn.net/qq_37969433/article/details/81189195
今日推荐