简体   繁体   English

在python中评估postfix?

[英]Evaluating postfix in python?

I want to write a fucnction to evaluate a postfix expression passed as a list. 我想编写一个功能来评估作为列表传递的后缀表达式。 So far I have got: 到目前为止,我已经:

def evalPostfix(text):
    s = Stack()
    for symbol in text:
        if symbol in "0123456789":
            s.push(int(symbol))
        if not s.is_empty():
            if symbol == "+":
                plus = s.pop() + s.pop()
            if symbol == "-":
                plus = s.pop() - s.pop()
            if symbol == "*":
                plus = s.pop() * s.pop()
            if symbol == "/":
                plus = s.pop() / s.pop()

But I think I have the wrong approach. 但是我认为我的方法是错误的。 Help? 救命?

You have a few problems: 您有一些问题:

  1. You are discarding the value after you come across an operator. 遇到运算符后,您将丢弃该值。 To fix this you have to push the result of any operator back to the stack and then proceed to the next step. 要解决此问题,您必须将任何运算符的结果推回堆栈,然后继续进行下一步。
  2. You do not skip the rest of the logic when come across a number (it is not going to make your code return a wrong answer, but still is not very smart) 遇到数字时,您不会跳过其余的逻辑(这不会使您的代码返回错误的答案,但仍然不是很聪明)
  3. Your function does not return anything. 您的函数不返回任何内容。

Something like this should work: 这样的事情应该起作用:

def eval_postfix(text):
    s = list()
    for symbol in text:
        if symbol in "0123456789":
            s.append(int(symbol))

        plus = None
        elif not s.is_empty():
            if symbol == "+":
                plus = s.pop() + s.pop()
            elif symbol == "-":
                plus = s.pop() - s.pop()
            elif symbol == "*":
                plus = s.pop() * s.pop()
            elif symbol == "/":
                plus = s.pop() / s.pop()
        if plus is not None:
            s.append(plus)
        else:
             raise Exception("unknown value %s"%symbol)
    return s.pop()

Here is a solution that may work for you. 这是一个可能适合您的解决方案。 I've tried to change your code as little as possible. 我试图尽可能少地更改您的代码。

Change #1: Rather than check whether symbol is between 0 and 9, you might simply try to convert symbol (which starts as a string ) to an int . 变更#1:您可以直接尝试将symbol (以string开头)转换为int ,而不是检查symbol是否在0到9之间。 If that succeeds, you can treat symbol as an operand. 如果成功,则可以将symbol视为操作数。 (This allows your code to handle multi-digit numbers.) (这使您的代码可以处理多位数的数字。)

Change #2: Raise an error if a non-number, non-operator occurs in text . 更改#2:如果text出现非数字非运算符,则会引发错误。 (You don't want anything else to be in there.) (您不希望其他任何内容。)

Change #3: Use eval instead of writing out each of the operators. 变更#3:使用eval而不是写出每个运算符。 eval comes with a lot of safety concerns, but I think here, since we're making sure everything is a number or an operator, we're OK. eval有很多安全方面的问题,但是我想在这里,因为我们确保所有内容都是数字或运算符,所以可以。

Change #4: Push intermediate results into the stack. 变更4:将中间结果推入堆栈。

Change #5: Return s.pop() after the list has been exhausted. 变更#5:清单用尽后返回s.pop() You might want to add a line that confirms that s contains just one value at this point. 您可能要添加一行以确认s此处仅包含一个值。

Caveat: Note that this code assumes that s will contain two values every time an operator is encountered. 注意:请注意,此代码假定s每次遇到运算符时都将包含两个值。 You might want to catch the error that would be raised if this were not true with another try / except pair of statements. 你可能想赶上,如果这是不是真的有另外一个将要引发的错误try / except对语句。

def evalPostfix(text):
    s = Stack()
    for symbol in text:
        try:
            result = int(symbol)
        except ValueError:
            if symbol not in '+-*/':
                raise ValueError('text must contain only numbers and operators')
            result = eval('%d %s %d' % (s.pop(), symbol, s.pop()))
        s.push(result)
    return s.pop() 

Hosane has provided a nicely detailed answer to your question, but there's one error that i think i see, although i'll admit im not an expert on this subject. Hosane为您的问题提供了很好的详细答案,但我认为我看到了一个错误,尽管我承认我不是该主题的专家。

Since you're using pop your calculation goes like this. 由于您使用的是流行音乐,因此您的计算将如下所示。 (last number in stack) (operator) (second last number in stack) for example if you have ["3","2","+"] in your list, you get 3+2 (堆栈中的最后一个数字)(运算符)(堆栈中的倒数第二个数字),例如,如果您的列表中有[“ 3”,“ 2”,“ +”],则得到3 + 2

this is fine for addition or multiplication, but if you take division or substraction this would result in the wrong answer. 这对于加法或乘法很好,但是如果您进行除法或减法运算,则会导致错误的答案。 for example (3-2) in post fix would be [3,2,-]. 例如,后修复中的(3-2)将为[3,2,-]。 Your code would calculate this as (2-3) when it should have been (3-2). 您的代码应该将其计算为(3-2)时将其计算为(2-3)。

So you should change the division and substraction if cases to; 因此,如果需要,您应该更改除法和减法;

elif symbol=="-":
        s.append(-stack.pop() + stack.pop())
elif symbol=="/":
        s.append(1/stack.pop() * stack.pop())

Working code that is translation of K&R C example, 工作代码是K&R C示例的翻译版本,

def eval_postfix(text):

    stack = []
    tokens = text.split(" ")

    for token in tokens:

        if token.strip() == '':
            continue 

        elif token == "+":
            stack.append(stack.pop() + stack.pop())

        elif token == "-":
            op2 = stack.pop() 
            stack.append(stack.pop() - op2)

        elif token == '*':
            stack.append(stack.pop() * stack.pop())

        elif token == '/':
            op2 = stack.pop()
            if op2 != 0.0:
                stack.append(stack.pop() / op2)
            else:
                raise ValueError("division by zero found!")

        elif (is_number(token)):
                stack.append(float(token))

        else:
            raise ValueError("unknown token {0}".format(token))


    return stack.pop()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM