如何使用逻辑运算符评估前缀表达式

Posted

技术标签:

【中文标题】如何使用逻辑运算符评估前缀表达式【英文标题】:how to evaluate prefix expression for with logical operator 【发布时间】:2018-01-18 06:45:25 【问题描述】:

我有一个带有多个 AND 和 OR 运算符的前缀表达式,创建了超过 1 的级别,我编写的算法在单个深度上工作正常,但在深度超过 1 时搞砸了结果。我正在使用 python

前缀列表:-['OR', 'AND', '=', ['.', 'grade'], 12, '>=', ['.', 'gpa'], ['.', '$', 'GPA'], 'AND', '=', ['.', 'a'], ['.', 'b'], '>', ['.', 'c'], ['.', 'd']]

def prefix_evaluation(prefix_list):
    opstack = []
    operand_stk = []
    pending_opd = False
    for token in prefix_list:
        if token in operators:
            opstack.append(token)
            pending_opd = False
        else:
            operand = token
            if pending_opd:
                while len(operand_stk) > 0:
                    opd_1 = operand_stk.pop()
                    operator  = opstack.pop()
                    operand = [operator, opd_1, operand]
            operand_stk.append(operand)
            pending_opd = True
    return operand_stk.pop()

预期结果:

[ OR,
    [ AND,
         [ AND,
              [ '=', ['.', 'grade'], 12],
              [ '>=', ['.', 'gpa'], ['.', '$', 'GPA']]
         ]
         [ AND,
              ['=', ['.', 'a'], ['.', 'b']],
              ['>', ['.', 'c'], ['.', 'd']]
         ]
    ]
]

实际结果:

['OR',
     ['AND', 
           ['AND', 
                ['=', ['.', 'grade'], 12], 
                ['>=', ['.', 'gpa'], 
                ['.', '$', 'GPA']]], 
           ['=', ['.', 'a'], ['.', 'b']]],
     ['>', ['.', 'c'], ['.', 'd']]]

【问题讨论】:

抛开一切,查找递归下降表达式解析或 Dijkstra Shunting-yard 算法。 【参考方案1】:

为了使列表更具可读性,我将12['.', 'grade']['.', 'c']等所有操作数都替换为n。另外,我已经用= 替换了所有算术运算符,例如'>=''>'

现在您的列表看起来像 OR AND = n n = n n AND = n n = n n

我使用圆括号、方括号和大括号来强调这些术语如何组合在一起——或者应该组合在一起

(= n n)实际上是一个由一个运算符和两个操作数组成的列表,如['>=', 12, 12]

显示预期结果与实际结果之间差异的图形透视图如下:

当程序解析子列表 OR AND = n n = n n 时,它将形成操作数 [AND (= n n) (= n n)] (以及仍在操作符堆栈中的额外 OR)。如您所见,此操作数对预期结果和实际结果都是通用的。

当程序解析子列表OR AND = n n = n n AND = n n(注意额外的AND = n n)时,它将具有已经形成的[AND (= n n) (= n n)]操作数,以及新的操作数AND和操作数(=n n) .它将分组为 AND [AND (= n n) (= n n)] (= n n) 。这就是程序的作用,它的编写方式。现在真的有办法告诉你的程序:嘿,需要形成第二个[AND (= n n) (= n n)],然后才将两者与OR 连接起来。

打个比方,这就像期望一个逐字符读取的解析器意识到 1+2*3 不是 (1+2)*3,而是 1+(2*3),除非您以某种方式指定乘法优先于加法。

这里的陷阱是您将算术和逻辑运算符放在同一个篮子里。难怪它们在构建表达式时具有相同的优先级(priority)。

更好的方法是区分算术表达式,例如 (= n n) 和像 [AND E1 E2] 这样的逻辑表达式,通过将它们放在两个不同的堆栈中,以及像 n 这样的基本操作数的第三个堆栈。还将算术运算符(如=)与逻辑运算符(如AND)放在不同的堆栈中。并且只有现在你可以强加规则 'AND' 运算符应该只链接两个算术或两个逻辑表达式,而不是一个算术与一个逻辑表达式,以避免你当前的输出并获得预计一个。

但我觉得堆栈方法很麻烦,最好按照某人的建议使用递归。

【讨论】:

以上是关于如何使用逻辑运算符评估前缀表达式的主要内容,如果未能解决你的问题,请参考以下文章

短路逻辑评估运算符

三元运算符可以等效于与逻辑运算符的短路吗?

短路评估顺序和前缀增量运算符

看过来,这里有JavaScript技术干货?

NAND、NOR、XNOR 的逻辑运算符优先级

当 lhs 为假时,为啥在逻辑 AND 中评估条件(三元)运算符