问题描述
小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
题解
首先明确问题需求,这个问题要求实现一个能够解析和计算简单数学表达式的计算器。表达式只包含数字(0-9)、加法(+)、减法(-)、乘法(*)、除法(/)以及括号(()),并且不包含空格。数字可以是多位数,除法运算应只保留整数结果。
解题关键
-
栈(Stack):栈是一种后进先出(LIFO)的数据结构,非常适合用于处理这种嵌套结构的问题。在这个问题中,我们使用栈来存储操作符和操作数。
-
运算符优先级:
- 乘法(*)和除法(/)的优先级高于加法(+)和减法(-)。
- 通过
precedence函数来定义每个运算符的优先级,帮助我们在计算时按正确顺序处理运算符。
-
括号处理:
- 左括号
(:直接被压入操作符栈,表示一个新的计算子表达式的开始。 - 右括号
):当前计算子表达式的结束,需要计算并弹出左括号之前的所有操作符。
- 左括号
-
操作符的比较与应用:
greater_precedence函数用于比较当前栈顶操作符的优先级与新遇到的操作符的优先级。- 如果栈顶操作符的优先级大于或等于新操作符的优先级,我们需要先计算栈顶操作符的结果,然后将新操作符压入栈。
-
多位数处理:
- 当遇到数字时,代码会继续读取直到遇到非数字字符,这样可以正确地组合成一个多位数。
代码详解
-
apply_operator函数:- 该函数接收一个操作符和两个操作数。
- 根据操作符的不同,执行相应的计算,并将结果压入操作数栈。
- 例如,如果是
+,则将left + right的结果压入操作数栈。
-
precedence函数:- 该函数定义了运算符的优先级。
+和-优先级为1,*和/优先级为2。 - 优先级高的运算符会先被计算。
- 该函数定义了运算符的优先级。
-
greater_precedence函数:- 该函数用于比较两个运算符的优先级。
- 返回
True如果第一个运算符的优先级大于或等于第二个运算符的优先级。
-
主逻辑:
- 遍历输入的数学表达式字符串,逐字符解析。
- 遇到数字时,将连续数字字符组合成一个完整的数字,并压入操作数栈。
- 遇到左括号
(时,压入操作符栈。 - 遇到右括号
)时,持续弹出并计算操作符栈顶运算符,直到遇到左括号(,然后将其弹出。 - 遇到运算符时,检查操作符栈顶运算符的优先级是否大于或等于当前运算符的优先级。如果是,则先处理栈顶运算符。
- 最后,如果操作符栈中还有剩余的运算符,持续弹出并计算,直到操作符栈为空。
- 最终,操作数栈中只剩下一个结果,这个结果即为表达式的值。
测试样例分析
-
样例1:
- 输入:
"1+1" - 输出:
2 - 解析:
1和1压入操作数栈,+压入操作符栈,遍历结束后计算1 + 1。
- 输入:
-
样例2:
- 输入:
"3+4*5/(3+2)" - 输出:
7 - 解析:先处理括号内的
3+2,得到5,然后处理4*5和5/5,最后计算3 + 4。
- 输入:
-
样例3:
- 输入:
"4+2*5-2/1" - 输出:
12 - 解析:先处理
2*5和2/1,然后计算4 + 10 - 2。
- 输入:
-
样例4:
- 输入:
"(1+(4+5+2)-3)+(6+8)" - 输出:
23 - 解析:先处理括号内的
(4+5+2)等子表达式,然后再计算整个表达式的值。
- 输入:
-
样例5:
- 输入:
"2*(5+5*2)/3+(6+8*3)" - 输出:
40 - 解析:先处理括号内的
(5+5*2)和(6+8*3),然后再计算整个表达式的值。
- 输入: