我正在尝试从字符串中解析多树。
语法:
root (树,树,树......)=
例如:
1(2,3,4(5,3),4(7,8,5))=
我想出了如何从字符串中解析二进制树:
我的代码:
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
答案 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))
取第一个字符,将其作为根节点。使其子数为0.设置当前节点= root。
下一个字符应为'(',按下堆栈上的最后一个节点rootHistory。将'('打开到堆栈newChildren。
阅读下一个字符。如果是数字,请创建一个新节点。使新节点的子节点数= 0.将此节点添加到名为children的节点的新向量中。您可以为每个节点创建一个子节点向量。
struct node {
int值;
int numOfChildren;
向量或节点数组:children [];
};
如果上面读到的字符是')',则从newChildren堆栈中弹出一个括号。从rootHistory弹出节点,并为其分配上次创建的子节点的矢量。