如何正确组合多个布尔后缀表达式?

时间:2015-08-18 19:52:49

标签: .net vb.net binary-tree postfix-notation rpn

我已经整理了一些代码,以便在postfix和infix之间进行转换,然后再回来。现在我试图采用单独的后缀表达式并将它们组合起来。

我的表达式只使用布尔运算符(NOT,XOR,AND,OR)。

请注意,表达式中的数字指的是最终被评估为true或false的规则。

目前,我遇到的问题是将表达式中没有的表达式组合在一起。

例如,我想使用AND:

将以下内容组合成单个后缀表达式
45 46 &
1 !
41 42 | 48 |
50 51 |

目前我的输出结果如下:

45 46 & 1 ! & 50 51 | & 41 42 | 48 | & 

但是当把它转换成中缀时,我(错误地)得到了这个(注意领先&):

( ( & ( 45 & 46 ) ! 1 ) & ( 50 | 51 ) ) & ( ( 41 | 42 ) | 48 )

我不确定这是否是用于组合表达式或后缀为中缀转换的代码的不足。

上面前4个表达式的AND组合的正确后缀表达式是什么?

我怀疑我的问题是我在转换或组合例程(或两者)中没有正确处理NOT运算符。

下面是组合代码,后跟转换代码。

组合:

Public Shared Function GetExpandedExpression(Expressions As List(of String)) As String
    'there is guaranteed to be at least one item in the list.
    ExpandedPostfixExpression = PostfixList(0) & " "
    If PostfixList.Count > 1 Then
        For i As Integer = 1 To PostfixList.Count - 1
            ExpandedPostfixExpression &= PostfixList(i) & " & "
        Next
    End If

    Return ExpandedPostfixExpression.TrimEnd
End Function

转换:

Public Class ExpressionConversion

    Private Class Intermediate
        Public expr As String
        Public oper As String
        Public Sub New(expr As String, oper As String)
            Me.expr = expr
            Me.oper = oper
        End Sub
    End Class

    Private Const Operators As String = "!&|*()"

    Private Shared Function IsOperator(elem As String) As Boolean
        Return Operators.Contains(elem)
    End Function

    Public Shared Function PostfixToInfix(postfix As String) As String
        'Adapted from http://www.codeproject.com/Articles/405361/Converting-Postfix-Expressions-to-Infix
        Dim stack = New Stack(Of Intermediate)()
        For Each token As String In postfix.Split(CChar(" "))
            If IsOperator(token) Then
                ' Get the intermediate expressions from the stack.  
                ' If an intermediate expression was constructed using a lower precedent
                ' operator (+ or -), we must place parentheses around it to ensure 
                ' the proper order of evaluation.
                Dim leftExpr As String = ""
                Dim rightExpr As String = ""

                Dim rightIntermediate = stack.Pop()
                If rightIntermediate.oper <> "" AndAlso Precedence(token) >= Precedence(rightIntermediate.oper) Then
                    rightExpr = "( " + rightIntermediate.expr + " )"
                Else
                    rightExpr = rightIntermediate.expr
                End If

                If stack.Count <> 0 Then 'in the case where there is only a unary op eg NOT - skip the following
                    Dim leftIntermediate = stack.Pop()
                    If leftIntermediate.oper <> "" AndAlso Precedence(token) >= Precedence(leftIntermediate.oper) Then
                        leftExpr = "( " + leftIntermediate.expr + " )"
                    Else
                        leftExpr = leftIntermediate.expr
                    End If
                End If
                ' construct the new intermediate expression by combining the left and right 
                ' using the operator (token).
                Dim newExpr = (leftExpr & " " & token & " " & rightExpr).Trim

                ' Push the new intermediate expression on the stack
                stack.Push(New Intermediate(newExpr, token))
            Else
                stack.Push(New Intermediate(token, ""))
            End If
        Next

        ' The loop above leaves the final expression on the top of the stack.
        Return stack.Peek().expr
    End Function

    Private Shared Function Precedence(op As String) As Integer
        Select Case op
            Case "!"
                Return 4
            Case "*"
                Return 3
            Case "&"
                Return 2
            Case "|"
                Return 1
        End Select
        Return 0
    End Function
End Class

更新

以下是标记答案产生的代码更改(在转换例程中):

替换它:

If stack.Count <> 0 

有了这个:

If stack.Count <> 0 And token <> "!"

1 个答案:

答案 0 :(得分:2)

如评论中所述,我认为如果它是一元运算符,则必须将表达式推回到堆栈,以成为下一个迭代RHS表达式。否则,以下操作符也将被处理为一元,导致您的情况在前导&amp;。