简单四则运算解析器
问题描述
小F面临一个编程挑战:实现一个基本的计算器来计算简单的字符串表达式的值。该字符串表达式有效,并可能包含数字(0-9)、运算符+、-及括号()。注意,字符串中不包含空格。除法运算应只保留整数结果。请实现一个解析器计算这些表达式的值,且不使用任何内置的eval函数。
测试样例
样例1:
输入:
expression = "1+1"
输出:2
样例2:
输入:
expression = "3+4*5/(3+2)"
输出:7
样例3:
输入:
expression = "4+2*5-2/1"
输出:12
样例4:
输入:
expression = "(1+(4+5+2)-3)+(6+8)"
输出:23
样例5:
输入:
expression = "2*(5+5*2)/3+(6+8*3)"
输出:40
问题理解
题目要求实现一个简单的四则运算解析器,能够计算包含数字、加减乘除运算符以及括号的字符串表达式的值。表达式中不包含空格,并且除法运算只保留整数结果。
数据结构选择
为了处理这种表达式,我们可以使用两个栈:
- 数字栈:用于存储表达式中的数字。
- 操作符栈:用于存储表达式中的操作符。
算法步骤
-
遍历表达式:从左到右遍历表达式的每个字符。
-
处理数字:如果当前字符是数字,将其转换为整数并压入数字栈。
-
处理左括号:如果当前字符是左括号
(,将其压入操作符栈。 -
处理右括号:如果当前字符是右括号
),则从操作符栈中弹出操作符,并从数字栈中弹出两个数字进行计算,直到遇到左括号(。 -
处理操作符:如果当前字符是操作符(
+、-、*、/),则根据操作符的优先级进行处理:- 如果操作符栈顶的操作符优先级高于或等于当前操作符,则先进行栈顶操作符的计算。
- 否则,将当前操作符压入操作符栈。
-
处理剩余操作符:遍历结束后,如果操作符栈中还有操作符,依次弹出并进行计算。
-
返回结果:最终数字栈中的唯一元素即为表达式的计算结果。
代码如下:
import java.util.*;
public class Main {
public static int solution(String expression) {
// 首先创建两个栈,一个用于存储数字,一个用于存储操作符
Stack<Integer> numStack = new Stack<>();
Stack<Character> opStack = new Stack<>();
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
if (Character.isDigit(c)) {
int num = c - '0';
numStack.push(num);
}
else if (c == '(') {
opStack.push(c);
}
else if (c == ')') {
while (!opStack.isEmpty() &&opStack.peek()!= '(') {
char op = opStack.pop();
int b = numStack.pop();
int a = numStack.pop();
numStack.push(calculate(a, b, op));
}
opStack.pop();
}
// 如果是操作符
else if (c == '+' || c == '-' || c == '*' || c == '/') {
while (!opStack.isEmpty() && opStack.peek() != '(' && precedence(c) <= precedence(opStack.peek())) {
char op = opStack.pop();
int b = numStack.pop();
int a = numStack.pop();
numStack.push(calculate(a, b, op));
}
opStack.push(c);
}
}
// 处理剩余的操作符
while (!opStack.isEmpty()) {
char op = opStack.pop();
int b = numStack.pop();
int a = numStack.pop();
numStack.push(calculate(a, b, op));
}
// 返回最终结果
return numStack.pop();
}
// 定义操作符的优先级
public static int precedence(char op) {
if (op == '+' || op == '-') {
return 1;
} else if (op == '*' || op == '/') {
return 2;
}
return 0;
}
public static int calculate(int a, int b, char op) {
switch (op) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
return a / b;
default:
throw new IllegalArgumentException("Invalid operator: " + op);
}
}
public static void main(String[] args) {
System.out.println(solution("1+1") == 2);
System.out.println(solution("3+4*5/(3+2)") == 7);
System.out.println(solution("4+2*5-2/1") == 12);
System.out.println(solution("(1+(4+5+2)-3)+(6+8)") == 23);
}
}
知识点总结:
1. 栈(Stack)
栈是一种后进先出(LIFO)的数据结构,非常适合用于解析和计算表达式。在这个问题中,我们使用两个栈:
- 数字栈:用于存储表达式中的数字。
- 操作符栈:用于存储表达式中的操作符。
2. 操作符优先级
在处理表达式时,操作符的优先级非常重要。我们需要根据操作符的优先级来决定何时进行计算。常见的优先级如下:
*和/的优先级高于+和-。- 括号
()可以改变运算顺序,需要优先处理。
3. 表达式解析
解析表达式时,我们需要从左到右遍历每个字符,并根据字符的类型进行不同的处理:
- 数字:将其转换为整数并压入数字栈。
- 左括号
(:将其压入操作符栈。 - 右括号
):从操作符栈中弹出操作符,并从数字栈中弹出两个数字进行计算,直到遇到左括号(。 - 操作符:根据操作符的优先级进行处理,如果当前操作符的优先级低于或等于栈顶操作符的优先级,则先进行栈顶操作符的计算。
通过上述知识点和代码示例,我们可以实现一个简单的四则运算解析器。