从字符串中解析多树

时间:2013-09-16 11:00:45

标签: vb.net algorithm parsing tree graph-algorithm

我正在尝试从字符串中解析多树。


语法:

root (树,树,树......)=

enter image description here

例如:

1(2,3,4(5,3),4(7,8,5))=

enter image description here


我想出了如何从字符串中解析二进制树:

我的代码:

Public Class Tree
Public l As Tree = Nothing
Public r As Tree = Nothing
Public value As String
Public Sub New(ByVal Str As String)
    If Str = "" Then Throw New Exception("Input String is Nothing ("""")")
    Dim Error_Report As String = RunCheck(Str)
    If Not Error_Report = "" Then Throw New Exception(Error_Report)
    If Str.Contains("(") Then
        Try
            value = Str.Substring(0, Str.IndexOf("("))
            BulidTreeByInTo(Str.Substring(Str.IndexOf("(") + 1, Str.Length - 2 - Str.IndexOf("(")), l, r)
        Catch ex As Exception
            Throw ex
        End Try
    Else
        value = Str
    End If
End Sub
Private Function RunCheck(ByVal str As String) As String
    Dim Open_Close As Integer = 0
    For i = 0 To str.Length - 1 Step 1
        If str(i).ToString = "(" Then
            Open_Close += 1
        ElseIf str(i).ToString = ")" Then
            Open_Close -= 1
        End If
        If i >= 1 Then
            If (str(i - 1).ToString = ")" And str(i).ToString = "(") Or (str(i - 1).ToString = "(" And str(i).ToString = ")") Then
                Return "Error in bracket At Index " & i
            End If
            If (str(i - 1).ToString = "(" And str(i).ToString = ",") Or (str(i - 1).ToString = "," And str(i).ToString = ")") Or (str(i - 1).ToString = "," And str(i).ToString = "(") Or (str(i - 1).ToString = "," And str(i).ToString = ",") Then
                Return "Error in Comma At Index " & i
            End If
        End If
    Next
    If Not Open_Close = 0 Then Return "Not all existing brackets are Closed"
    Return ""
End Function
Private Function GetTheSameLevel(ByVal s As String) As Integer
    Dim level As Integer = 0
    For i = 0 To s.Length - 1 Step 1
        If s(i).ToString = "," And level = 0 Then
            Return i
        End If
        If s(i).ToString = "(" Then
            level += 1
        End If
        If s(i).ToString = ")" Then
            level -= 1
        End If
    Next
    Return -1
End Function
Private Sub BulidTreeByInTo(ByVal str As String, ByRef l1 As Tree, ByRef r1 As Tree)
    Dim MiddleIndex As Integer = GetTheSameLevel(str)
    Dim p1 As String = str.Substring(0, MiddleIndex)
    Dim p2 As String = str.Substring(MiddleIndex + 1, str.Length - 1 - MiddleIndex)
    Try
        If p1.Contains("(") Then
            If Not p1.Substring(0, p1.IndexOf("(")).ToString = "\" Then
                l1 = New Tree(p1.Substring(0, p1.IndexOf("(")))
                BulidTreeByInTo(p1.Substring(p1.IndexOf("(") + 1, p1.Length - 2 - p1.IndexOf("(")), l1.l, l1.r)
            End If
        Else
            If Not p1 = "\" Then
                l1 = New Tree(p1)
            End If
        End If
        If p2.Contains("(") Then
            If Not p2.Substring(0, p2.IndexOf("(")).ToString = "\" Then
                r1 = New Tree(p2.Substring(0, p2.IndexOf("(")))
                BulidTreeByInTo(p2.Substring(p2.IndexOf("(") + 1, p2.Length - 2 - p2.IndexOf("(")), r1.l, r1.r)
            End If
        Else
            If Not p2 = "\" Then
                r1 = New Tree(p2)
            End If
        End If
    Catch ex As Exception
        Throw ex
    End Try
End Sub
End Class

2 个答案:

答案 0 :(得分:2)

您需要做的是概括您​​的代码:目前它只假设两个孩子,而您的Tree类有字段

Public l As Tree = Nothing
Public r As Tree = Nothing

但你不再知道每棵树有多少个孩子,所以你需要一个集合:List是一个合理的选择

Public children As List(Of Tree) = New List(Of Tree)

请注意,这会初始化为空:您需要在发现时添加子项。

现在您需要查看解析字符串并查找子项的代码。目前你有一个功能

Private Sub BulidTreeByInTo(ByVal str As String, ByRef l1 As Tree, ByRef r1 As Tree)

这应该改为

Private Sub BulidTreeByInTo(ByVal str As String, ByRef ch As List(Of Tree))

最后,您需要修改BulidTreeByInTo的实现,以便它使用循环来添加ch所需的子项。因此,您不需要对两个几乎相同的If ... Else ... End If块进行硬编码,而是需要在循环中只使用其中一个块。我建议采取以下措施

Do
    Dim MiddleIndex As Integer = GetTheSameLevel(str) ' find comma at same level
    Dim p1 As String = str.Substring(0, MiddleIndex) ' substring up to this comma
    ' str is rest of string past the comma, which can be 0 or more children
    str = str.Substring(MiddleIndex + 1, str.Length - 1 - MiddleIndex)
    Try
        If p1.Contains("(") Then
            If Not p1.Substring(0, p1.IndexOf("(")).ToString = "\" Then
                ch.Add(New Tree(p1.Substring(0, p1.IndexOf("("))))
                BulidTreeByInTo(p1.Substring(p1.IndexOf("(") + 1, p1.Length - 2 - p1.IndexOf("(")), l1.ch)
            End If
        Else
            If Not p1 = "\" Then
                ch.Add(New Tree(p1))
            End If
        End If
    Catch ex As Exception
        Throw ex
    End Try
While MiddleIndex >= 0

在我看来,您的函数GetTheSameLevel在同一级别找到下一个逗号,如果找不到逗号则返回<0,因此<0是循环终止条件。我们的想法是保留大部分现有代码,但不是将p2作为右侧字符串,而是将右侧字符串重新分配给str。每次我们完成循环操作时,我们会从str中删除下一位并分配给p1

我不是VB程序员,并没有编译或测试过这个,但希望这能让你对如何继续进行充分的了解?

答案 1 :(得分:1)

以下内容应该让您了解如何处理:

1(2,3,4(5,3),4(7,8,5))

  1. 取第一个字符,将其作为根节点。使其子数为0.设置当前节点= root。

  2. 下一个字符应为'(',按下堆栈上的最后一个节点rootHistory。将'('打开到堆栈newChildren。

  3. 阅读下一个字符。如果是数字,请创建一个新节点。使新节点的子节点数= 0.将此节点添加到名为children的节点的新向量中。您可以为每个节点创建一个子节点向量。

    struct node {
      int值;
      int numOfChildren;
      向量或节点数组:children [];
    };

  4. 如果上面读到的字符是')',则从newChildren堆栈中弹出一个括号。从rootHistory弹出节点,并为其分配上次创建的子节点的矢量。