Bootstrap

表达式求值

表达式求值

给定一个字符串,它只包含 ()* - + /和数字。计算出表达式。

使用递归的方式实现。 在这里讲一下思路。

整体思路:

使用 process(String str) 函数进行递归。当遇到计算符号的时候,则按照计算符号进行切分。例如,1 + 2 则切分为 process("1") + process("2")。具体的规则如下:

  1. 当计算符号是 ( 的时候,则找到与其配对的 ), 然后切分为 process(before + result + after ) , 其中 before 是 ( 前面的字符串,after 是 )的字符串,result 是 ( ) 里面表达式的计算结果。
  2. 优先截断 + - 两个计算符号,* \ 放在其后面。这样就能保证乘除法比加减法优先级第了。

上代码:

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String expression = in.nextLine();
            System.out.println(process(expression));
        }
    }
    public static final String PLUS = "+";
    public static final String M = "-";
    public static final String START = "*";
    public static final String D = "/";
    public static final String L = "(";
    public static final String R = ")";

    public static int process(String expression){
        // 使用 lastIndexOf 从后往前找计算符号,可以保证从左往右计算的顺序
        int position = expression.lastIndexOf(L);
        if(-1 != position){
            String sub = expression.substring(position+1);
            char[] chars = sub.toCharArray();
            int cnt = 0 ;
            int i = 0 ;
            /*
            会遇到这种情况,(1 + (1 + 3)) , 需要从 position 位置,往后找到与其匹配的 ) d
            cnt 是为了记录是否 position 和 ) 之间是否有成对的括号。遇到 ( ++ , 遇到 ) --
            这样的话, 当遇 cnt == 0 && chars[i] == ')' 的条件成立的时候,也就是走过了
            成对的小括号,找到了与第一个左括号匹配的右括号。
            */
            while (!(cnt == 0 && chars[i] == ')')){
                if('(' == chars[i]){
                    cnt++;
                }else if(')' == chars[i]){
                    cnt--;
                }
                i++;
            }
            String rs = process(sub.substring(0, i)) + "";
            return process(expression.substring(0 , position) + rs + (i == sub.length()-1? "" : sub.substring(i+1)));
        }
        position = expression.lastIndexOf(PLUS);
        /*
         减号的情况比较复杂,例如,10 - 9*-1 , -1*-1 -1
         1)当遇到 -1 的情况,使用正则表达式判断一下即可,
         2)当遇到 10 - 9*-1 的情况,需要往前找到一个前面是数字后面是减号的情况。
         3)当遇到 -1*-1 的情况,p2 = 0 , 此时其实没有减号,里面只有负号,此时让 p2 = -1 。
         其实可以让 1) 和 3) 的情况合并在一起。
        */
        if(expression.matches("\\-\\d+")){
            return Integer.parseInt(expression);
        }
        int p2 = expression.lastIndexOf(M);
        int startIndex = (-1 == p2 ? -1 : p2 -1) ;
        while( startIndex>=0 && p2 >= 1 && !('0' <= expression.charAt(p2-1) && expression.charAt(p2-1) <= '9' && '-' == expression.charAt(p2))  ){
            p2 = expression.lastIndexOf(M , startIndex);
            if(-1 == p2) break ;
            startIndex = p2 - 1 ;
        }
        if(p2 == 0){
            p2 = -1 ;
        }
        if(position > p2 && -1 != position){
            return process(expression.substring(0 , position)) + process(expression.substring(position+1));
        }
        if(position < p2 && -1 != p2){
            return process(expression.substring(0 , p2)) - process(expression.substring(p2+1));
        }

        position = expression.lastIndexOf(START);
        p2 = expression.lastIndexOf(D);
        if(position > p2 && -1 != position){
            return process(expression.substring(0 , position)) * process(expression.substring(position+1));
        }
        if(position < p2 && -1 != p2){
            return process(expression.substring(0 , p2)) / process(expression.substring(p2+1));
        }
        return Integer.parseInt(expression);
    }
}

AST Tree 的方式,者中方式其实本质上也是递归的方式。

;