小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
要实现一个基本的计算器解析器,我们需要处理运算符的优先级和括号。以下是一个可能的实现方法,使用两个栈(stack):一个用于存储数字,另一个用于存储运算符。这个算法被称为 Shunting Yard 算法,它将中缀表达式转换为后缀表达式,然后进行计算。
注:Shunting Yard算法的名字来源于其操作过程与铁路调度场的操作类似。这个算法是由Edsger Dijkstra发明的,用于将中缀表达式转换为后缀表达式(逆波兰表示法)。在铁路调度场中,火车车厢被推到不同的轨道上,以便它们可以按照正确的顺序被重新组合成列车。类似地,Shunting Yard算法使用栈来暂存操作符,并根据操作符的优先级和结合性将它们重新排序,最终生成一个后缀表达式,这个表达式可以按照从左到右的顺序直接计算,而不需要括号来指示操作顺序 。
算法的核心在于用栈暂存操作符以备“调度”,比较新符号和栈顶原有符号的优先级,选择其中更容易结合的(根据优先级、结合方向)出栈——更容易结合就意味着更早地参与计算 。这个过程类似于铁路调度场中调度火车车厢的操作,因此得名“Shunting Yard算法” 。
- 定义运算符的优先级:
- 加(+)和减(-)的优先级为 1。
- 乘(*)和除(/)的优先级为 2。
- 括号(())用于改变运算顺序。
- 使用两个栈:
- 一个栈用于存储数字(数字栈)。
- 另一个栈用于存储运算符(运算符栈)。
- 遍历表达式:
- 从左到右遍历表达式的每个字符。
- 如果是数字,将其推入数字栈。
- 如果是运算符,比较其优先级,并在需要时将其推入运算符栈,或者从运算符栈中弹出运算符进行计算。
- 如果是左括号,直接推入运算符栈。
- 如果是右括号,弹出运算符栈中的运算符并计算,直到遇到左括号。
- 计算后缀表达式:
- 遍历完成后,运算符栈中可能仍有运算符,将它们依次弹出并计算。
以下是这个问题的 Python 代码实现:
def solution(expression):
def precedence(op):
if op in ('+', '-'):
return 1
if op in ('*', '/'):
return 2
return 0
def apply_op(a, b, op):
if op == '+': return a + b
if op == '-': return a - b
if op == '*': return a * b
if op == '/': return int(a / b) # 保留整数结果
def parse_expression(expr):
values = []
ops = []
i = 0
while i < len(expr):
if expr[i].isdigit():
j = i
while i + 1 < len(expr) and expr[i + 1].isdigit():
i += 1
values.append(int(expr[j:i+1]))
elif expr[i] == '(':
ops.append(expr[i])
elif expr[i] == ')':
while ops[-1] != '(':
val2 = values.pop()
val1 = values.pop()
op = ops.pop()
values.append(apply_op(val1, val2, op))
ops.pop() # Pop the '('
else:
while (len(ops) != 0 and
precedence(ops[-1]) >= precedence(expr[i])):
val2 = values.pop()
val1 = values.pop()
op = ops.pop()
values.append(apply_op(val1, val2, op))
ops.append(expr[i])
i += 1
while len(ops) != 0:
val2 = values.pop()
val1 = values.pop()
op = ops.pop()
values.append(apply_op(val1, val2, op))
return values[0]
return parse_expression(expression)
# Example usage
print(solution("1+1")) # Output: 2
print(solution("3+4*5/(3+2)")) # Output: 7
print(solution("4+2*5-2/1")) # Output: 12
print(solution("(1+(4+5+2)-3)+(6+8)")) # Output: 23
print(solution("2*(5+5*2)/3+(6+8*3)")) # Output: 40
这段代码定义了一个 calculate 函数,它接受一个字符串表达式并返回计算结果。函数内部定义了 precedence 函数来确定运算符的优先级,apply_op 函数来应用运算符,以及 parse_expression 函数来解析和计算表达式。对于给定的例子,输出分别是 2、7、12、23 和 40。