我遇到问题的问题是计算后缀形式表达式:例如,(1,2,' +',3,' *') 。
使用以下算法计算表达式: 1.如果表达式只包含整数,则返回该整数。 2.否则,保持堆叠。循环遍历元组并将每个元素推送到堆栈。如果元素是运算符,则将前两个元素弹出堆栈,计算结果并将结果推入堆栈。 为了说明,我们采用上面的例子。最初,堆栈是空的。 测试案例是
calculate((1, 2, '*', 3, '-', 2, '*', 5, '+'))
3
而我的第一个代码并不好(硬编码且所有><):
def calculate(inputs):
if len(inputs) ==1:
return inputs[0]
elif len(inputs) == 5:
s= []
push_stack(s, inputs[0])
push_stack(s, inputs[1])
if inputs[2] == '*':
A = s.pop() * s.pop()
elif inputs[2] == '+':
A = s.pop() + s.pop()
elif inputs[2] == '-':
A= s.pop() - s.pop()
elif inputs[2] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[3])
if inputs[4] == '*':
A = s.pop() * s.pop()
elif inputs[4] == '+':
A = s.pop() + s.pop()
elif inputs[4] == '-':
A= s.pop() - s.pop()
elif inputs[4] == '/':
A = s.pop() / s.pop()
return A
else:
s= []
push_stack(s, inputs[0])
push_stack(s, inputs[1])
if inputs[2] == '*':
A = s.pop() * s.pop()
elif inputs[2] == '+':
A = s.pop() + s.pop()
elif inputs[2] == '-':
A= s.pop() - s.pop()
elif inputs[2] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[3])
if inputs[4] == '*':
A = s.pop() * s.pop()
elif inputs[4] == '+':
A = s.pop() + s.pop()
elif inputs[4] == '-':
A= s.pop() - s.pop()
elif inputs[4] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[5])
if inputs[6] == '*':
A = s.pop() * s.pop()
elif inputs[6] == '+':
A = s.pop() + s.pop()
elif inputs[6] == '-':
A= s.pop() - s.pop()
elif inputs[6] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[7])
if inputs[8] == '*':
A = s.pop() * s.pop()
elif inputs[8] == '+':
A = s.pop() + s.pop()
elif inputs[8] == '-':
A= s.pop() - s.pop()
elif inputs[8] == '/':
A = s.pop() / s.pop()
return A
很抱歉让你读到这个!然后我将风格改为
def calculate(inputs):
if len(inputs) ==1:
return inputs[0]
else:
s =[]
for i in inputs:
if type(i) == int:
return push_stack(s, i)
elif i is '*' or '/' or 'x' or '+':
A = s.pop()
B =s.pop()
know = operator(i, A, B)
C = push_stack(s, know)
return C
def operator(sign, one, two):
if sign == '*':
A = one * two
elif sign == '+':
A = one + two
elif sign == '-':
A= one - two
elif sign == '/':
A = one / two
return A
我是否接近这个想法以及我的代码如何改进?
**编辑** 使用IDLE:
>>> calculate((1, 2, '*', 3, '-'))
[1]
>>> calculate((1, 2, '+', 3, '*'))
[1]
>>> calculate((1, 2, '*', 3, '-', 2, '*', 5, '+'))
[1]
这不是我正在寻找的答案。它应该是1然后是9然后是3。
答案 0 :(得分:4)
有问题
elif i is '*' or '/' or 'x' or '+':
被视为
elif (i is '*') or ('/') or ('x') or ('+'):
这不是你想要的(它总是如此)。你可以使用类似的东西:
elif i in ('*', '/', 'x', '+'):
此外:
if type(i) == int:
return push_stack(s, i)
你不应该回到那里。你只想要:
if type(i) == int:
push_stack(s, i)
最后,我认为更好的方法是始终使用堆栈,并在函数结束时返回堆栈顶部。这使您无需为calculate()
的单元素参数创建特殊情况。把这一切放在一起,有些事情应该有效:
def calculate(inputs):
stack = []
for a in inputs:
if type(a) is int:
stack.append(a)
continue
op1, op2 = stack.pop(), stack.pop()
if a == '+':
stack.append(op2 + op1)
elif a == '-':
stack.append(op2 - op1)
elif a == '*':
stack.append(op2 * op1)
elif a == '/':
stack.append(op2 / op1)
return stack.pop()
现在这不会进行错误检查(例如表格格式不正确),但很容易添加。
答案 1 :(得分:4)
您似乎已经意识到的部分问题是,您正在尝试让一个功能完成所有操作。如果您查看代码正在执行的操作,并尝试分离职责,您最终会得到以下内容:
Python 2.x和3.x之间存在一些重要的区别。如果这些差异会导致问题,最简单的方法是引入辅助函数并为每个版本适当地定义它们:
import sys
if sys.hexversion < 0x3000000:
# Python 2.x
is_str = lambda s: isinstance(s, basestring)
inp = raw_input
else:
# Python 3.x
is_str = lambda s: isinstance(s, str)
inp = input
你做了一些堆栈维护;这可以通过创建一个知道如何弹出和推送多个项目的Stack类来避免。 (它也应该有助于你的无序参数问题; 4 2 -
应该是4 - 2,而不是2 - 4)
class Stack(list):
def pop_n(self, n):
"""
Pop n items off stack, return as list
"""
assert n >= 0, "Bad value {}: n cannot be negative".format(n)
if n == 0:
return []
elif n <= len(self):
res = self[-n:]
del self[-n:]
return res
else:
raise ValueError("cannot pop {} items, only {} in stack".format(n, len(self)))
def push_n(self, n, items):
"""
Push n items onto stack
"""
assert n == len(items), "Expected {} items, received {}".format(n, len(items))
self.extend(items)
我们可以让每个运算符都有自己独立的代码,而不是只使用一个“do-any-operation”函数。这使得更改或添加运算符更容易,没有有趣的副作用。首先我们创建一个Operator类
class Op:
def __init__(self, num_in, num_out, fn):
"""
A postfix operator
num_in: int
num_out: int
fn: accept num_in positional arguments,
perform operation,
return list containing num_out values
"""
assert num_in >= 0, "Operator cannot have negative number of arguments"
self.num_in = num_in
assert num_out >= 0, "Operator cannot return negative number of results"
self.num_out = num_out
self.fn = fn
def __call__(self, stack):
"""
Run operator against stack (in-place)
"""
args = stack.pop_n(self.num_in) # pop num_in arguments
res = self.fn(*args) # pass to function, get results
stack.push_n(self.num_out, res) # push num_out values back
然后我们将实际运算符定义为
ops = {
'*': Op(2, 1, lambda a,b: [a*b]), # multiplication
'/': Op(2, 1, lambda a,b: [a//b]), # integer division
'+': Op(2, 1, lambda a,b: [a+b]), # addition
'-': Op(2, 1, lambda a,b: [a-b]), # subtraction
'/%': Op(2, 2, lambda a,b: [a//b, a%b]) # divmod (example of 2-output op)
}
现在支持结构已经到位,您的评估功能就是
def postfix_eval(tokens):
"""
Evaluate a series of tokens as a postfix expression;
return the resulting stack
"""
if is_str(tokens):
# if tokens is a string, treat it as a space-separated list of tokens
tokens = tokens.split()
stack = Stack()
for token in tokens:
try:
# Convert to int and push on stack
stack.append(int(token))
except ValueError:
try:
# Not an int - must be an operator
# Get the appropriate operator and run it against the stack
op = ops[token]
op(stack) # runs Op.__call__(op, stack)
except KeyError:
# Not a valid operator either
raise ValueError("unknown operator {}".format(token))
return stack
为了让测试更容易,我们可以让它更具互动性:
def main():
while True:
expr = inp('\nEnter a postfix expression (or nothing to quit): ').strip()
if expr:
try:
print(" => {}".format(postfix_eval(expr)))
except ValueError as error:
print("Your expression caused an error: {}".format(error))
else:
break
if __name__=="__main__":
main()
这就像
一样Enter a postfix expression (or nothing to quit): 1 2 * 3 -
=> [-1]
Enter a postfix expression (or nothing to quit): 1 2 + 3 *
=> [9]
Enter a postfix expression (or nothing to quit): 1 2 * 3 - 2 * 5 +
=> [3]
Enter a postfix expression (or nothing to quit): 5 2 /%
=> [2, 1]
答案 2 :(得分:-1)
如果您正在使用计算器或类似的东西,则应使用函数eval()
。
它将返回表达式的结果。