表达式求值
给定一个字符串,它只包含 (
、)
、*
-
+
/
和数字。计算出表达式。
使用递归的方式实现。 在这里讲一下思路。
整体思路:
使用 process(String str) 函数进行递归。当遇到计算符号的时候,则按照计算符号进行切分。例如,1 + 2
则切分为 process("1") + process("2")
。具体的规则如下:
- 当计算符号是
(
的时候,则找到与其配对的)
, 然后切分为 process(before + result + after ) , 其中 before 是(
前面的字符串,after 是)
的字符串,result 是(
)
里面表达式的计算结果。 - 优先截断
+
-
两个计算符号,*
\
放在其后面。这样就能保证乘除法比加减法优先级第了。
上代码:
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 的方式,者中方式其实本质上也是递归的方式。