简体   繁体   English

在不使用多个函数的情况下使用python评估数学表达式的算法

[英]Algorithm for evaluating maths expressions using python without using multiple functions

I am trying to evaluate infix expressions using Stacks in python. 我正在尝试使用python中的Stacks评估中缀表达式。

I want to know if I have the following infix expressions below: 我想知道下面是否有以下中缀表达式:

'2 ^ ( 1 + 3 ^ 2 )'
'( 3 * 5 ) - ( 1 > 2 > 3 < 4 )'
'4 ^ ( 10 < 2 ) / 5 + 100'

how I would go on about evaluating this using 2 stacks and not calling upon multiple other functions, so that the output would be: 我将如何使用2个堆栈而不是调用多个其他函数来对此进行评估,以便输出为:

1024
12
103

I'm just wondering what the algorithm would be to do this. 我只是想知道执行此操作的算法是什么。 I know the standard way is to change the infix to postfix and then solve, but is there a quicker way to do this in one single function. 我知道标准方法是将后缀更改为后缀,然后再解决,但是有没有一种更快的方法可以在单个函数中完成此操作。 Thank you very much. 非常感谢你。

You might want to search for the "shunting yard algorithm" . 您可能要搜索“调车场算法” It's a pretty fundamental expression evaluation algorithm, and it uses two stacks (although one is called the 'output queue'). 这是一个非常基本的表达式评估算法,它使用两个堆栈(尽管其中一个称为“输出队列”)。

Basically, you filter numbers from operators. 基本上,您从运营商处过滤数字。 Numbers go onto the output stack, operators go onto the "holding" stack. 数字进入输出堆栈,运算符进入“持有”堆栈。 When an operator comes along that has lower precedence than what's on the holding stack, you move the contents of the holding stack to the output stack until either the holding stack is empty, or the item on the holding stack has lower precedence than the input operator. 当运算符的优先级比保持堆栈中的优先级低时,您可以将保持堆栈的内容移至输出堆栈,直到保持堆栈为空,或者保持堆栈中的项的优先级低于输入运算符。

Precedence 优先权

Remember that a + b * c - d is evaluated as (a + (b*c)) - d . 请记住, a + b * c - d的求值为(a + (b*c)) - d Remember also that exponentiation has higher precedence than multiplication, so a * b ^ c is going to be a * (b ^ c) . 还要记住,幂运算的优先级比乘法高,因此a * b ^ c将成为a * (b ^ c)

EDIT: 编辑:

Here's some code that doesn't work. 这是一些无效的代码。 I don't know what your operators '>' and '<' are. 我不知道您的运算符'>'和'<'是什么。 Apparently (10 < 2) should be 2, from the third expression? 从第三个表达式来看,显然(10 <2)应该是2吗?

I just implemented them as C-style booleans (1 for true, 0 false). 我只是将它们实现为C风格的布尔值(1表示true,0表示false)。

There's a heap of redundant code in there, because only one function. 因为只有一个函数,所以里面有很多冗余代码。 Feel free to clean that up. 随时清理它。 It modifies the Shunting Yard algorithm to perform the RPN computations on the fly. 它修改了Shunting Yard算法以即时执行RPN计算。 I've left in a bunch of print statements that illustrate the contents of the lists that I'm using as stacks. 我留下了一堆打印语句,这些语句说明了我用作堆栈的列表的内容。 Feel free to do a proper job with your stack classes. 随意对您的堆栈类做适当的工作。 In my version, pop() is pop, and append() is push. 在我的版本中, pop()是pop, append()是push。

tests = [
    '2 ^ ( 1 + 3 ^ 2 )',
    '( 3 * 5 ) - ( 1 > 2 > 3 < 4 )',
    '4 ^ ( 10 < 2 ) / 5 + 100',
]

expected = [
    1024,
    12,
    103,
]

def expr_eval(s):
    print("EXPR:", s)
    tokens = s.split()
    output_stk = []
    operator_stk = []

    precedence = {
        '(': 0,
        '+':1, '-':1, '<':1, '>':1,
        '*':2, '/':2,
        '^':3,
    }

    for t in tokens:
        print("OUT:", output_stk, "OP:", operator_stk)
        print("Tok: ",t)
        if t.isdigit():
            output_stk.append(int(t))
            continue
        elif t == '(':
            operator_stk.append(t)
            continue
        elif t == ')':
            # End of subexpression. Do math until we find opening (
            while operator_stk:
                op = operator_stk.pop()
                if op == '(':
                    break

                b = output_stk.pop()
                a = output_stk.pop()
                if op == '-': output_stk.append(a - b)
                elif op == '+': output_stk.append(a + b)
                elif op == '<': output_stk.append(1 if a < b else 0)
                elif op == '>': output_stk.append(1 if a > b else 0)
                elif op == '*': output_stk.append(a * b)
                elif op == '/': output_stk.append(a // b)
                elif op == '^': output_stk.append(a ** b)
                else:
                    raise Exception("Unknown operator: %s" % op)
                print("OUT:", output_stk, "OP:", operator_stk)
            continue

        # Not a number - check operator precedence
        prec_t = precedence[t]
        while operator_stk and prec_t <= precedence[operator_stk[-1]]:
            print("OUT:", output_stk, "OP:", operator_stk)
            op = operator_stk.pop()
            b = output_stk.pop()
            a = output_stk.pop() # 'a' went on first!
            if op == '-': output_stk.append(a - b)
            elif op == '+': output_stk.append(a + b)
            elif op == '<': output_stk.append(1 if a < b else 0)
            elif op == '>': output_stk.append(1 if a > b else 0)
            elif op == '*': output_stk.append(a * b)
            elif op == '/': output_stk.append(a // b)
            elif op == '^': output_stk.append(a ** b)
            else:
                raise Exception("Unknown operator: %s" % op)
        operator_stk.append(t)

    print("OUT:", output_stk, "OP:", operator_stk)

    while operator_stk:
        op = operator_stk.pop()
        if op == '(':
            raise Exception('Mismatched opening parenthesis!')

        b = output_stk.pop()
        a = output_stk.pop() # 'a' went on first!
        if op == '-':   output_stk.append(a - b)
        elif op == '+': output_stk.append(a + b)
        elif op == '<': output_stk.append(1 if a < b else 0)
        elif op == '>': output_stk.append(1 if a > b else 0)
        elif op == '*': output_stk.append(a * b)
        elif op == '/': output_stk.append(a // b)
        elif op == '^': output_stk.append(a ** b)
        else:
            raise Exception("Unknown operator: %s" % op)
        print("OUT:", output_stk, "OP:", operator_stk)

    return output_stk.pop()

for i in range(len(tests)):
    r = expr_eval(tests[i])
    if r == expected[i]:
        print("PASS: %d = %s" % (r, tests[i]))
    else:
        print("FAIL: %d != %d = %s" % (r, expected[i], tests[i]))

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

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