I am trying to parse a Multi - Tree from a String.
The Syntax :
root (Tree,Tree,Tree ...) =
For example :
1(2,3,4(5,3),4(7,8,5)) =
I figured out how to parse binary trees from strings:
My Code :
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
What you need to do is to generalize your code: at the moment it assumes exactly two children, and your Tree
class has fields
Public l As Tree = Nothing
Public r As Tree = Nothing
but you no longer know how many children each tree has, so you need a collection: List
is a reasonable choice
Public children As List(Of Tree) = New List(Of Tree)
Note that this is initialized to empty: you'll need to add children to it as you discover it.
Now you need to look at the code that parses the string and finds the children. At the moment you have a function
Private Sub BulidTreeByInTo(ByVal str As String, ByRef l1 As Tree, ByRef r1 As Tree)
This should change to
Private Sub BulidTreeByInTo(ByVal str As String, ByRef ch As List(Of Tree))
Finally you need to modify the implementation of BulidTreeByInTo
so that it uses a loop to add as many children as are needed to ch
. So, rather than hardcoding the two almost-identical If ... Else ... End If
blocks, you need to have just one of those blocks in a loop. I suggest something along the following lines
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
It looks to me like your function GetTheSameLevel
finds the next comma at the same level and returns <0
if it fails to find the comma, so <0
is the loop termination condition. The idea is that we keep most of your existing code and but rather than having p2
as the right-hand string, we reassign the right-hand string to str
. Each time we go through the loop we chop the next bit out of str
and assign to p1
.
I'm not a VB programmer and haven't compiled or tested this, but hopefully this gives you enough of an idea of how to proceed?
Following should give you an idea on how to approach:
1(2,3,4(5,3),4(7,8,5))
Take first character, make it the root node. Make its number of children 0. Set current node = root.
Next character shall be a '(', push the last node created on a stack rootHistory. Push the '(' on to a stack newChildren.
Read next character. If it is a numeral, create a new node. Make new node's number of children = 0. Add this to a new vector of nodes called children. You can have a vector of children nodes for each node.
struct node {
int value;
int numOfChildren;
vector or array of nodes: children[];
};
If the character read above is a ')', pop out a bracket from the newChildren stack. Pop out the node from the rootHistory, and assign it the vector of children last created.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.