堆栈计算器(后缀,Python)

时间:2014-03-22 14:49:36

标签: python

我遇到问题的问题是计算后缀形式表达式:例如,(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。

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()。 它将返回表达式的结果。