Private Const INIT_CAPACITY = 1
Public Class Comparison
Public Function Compare(lhs As Variant, rhs As Variant) As Integer
End Function
End Class
Public Class IntegerComparison As Comparison
Public Function Compare(lhs As Variant, rhs As Variant) As Integer
Compare = lhs - rhs
End Function
End Class
Public Class StringComparison As Comparison
Public Function Compare(lhs As Variant, rhs As Variant) As Integer
If lhs < rhs Then
Compare = -1
Else
If lhs = rhs Then
Compare = 0
Else
Compare = 1
End If
End If
End Function
End Class
Private Class BinaryNode
Public element As Variant
Public left As BinaryNode
Public right As BinaryNode
Public Sub New(element As Variant, _
lt As BinaryNode, rt As BinaryNode)
If RequiresSet(element) Then
Set Me.element = element
Else
Me.element = element
End If
Set Me.left = lt
Set Me.right = rt
End Sub
End Class
Public Class BinarySearchTree
Private root As BinaryNode
Private comp As Comparison
Public Sub New(comp As Comparison)
Set Me.comp = comp
Set root = Nothing
End Sub
Public Function Add(element As Variant) As Variant
Dim found As Variant
found = False
Set root = AddRecursively(element, root, found)
Add = Not found
End Function
Public Function Elements() As Variant
If Me.IsEmpty Then
Set Elements = Nothing
Exit Function
End If
Dim result() As Variant
Redim result(INIT_CAPACITY - 1) As Variant
Dim ndx As Long
ndx = 0
CollectElements root, result, ndx
Redim Preserve result(ndx - 1)
Elements = Result
End Function
Public Function Remove(element As Variant) As Variant
Dim found As Variant
found = False
Set root = RemoveRecursively(element, root, found)
Me.Remove = found
End Function
Public Function Contains(element As Variant) As Variant
Contains = Not Find(element, root) Is Nothing
End Function
Public Sub Clear
Set root = Nothing
End Sub
Public Function Min As Variant
Dim tmp As BinaryNode
Set tmp = FindMin(root)
If tmp Is Nothing Then
Set Me.Min = Nothing
Else
Min = tmp.element
End If
End Function
Public Function Max As Variant
Dim tmp As BinaryNode
Set tmp = FindMax(root)
If tmp Is Nothing Then
Set Me.Max = Nothing
Else
Max = tmp.element
End If
End Function
Private Function FindMin(t As BinaryNode) As BinaryNode
If t Is Nothing Then
Set FindMin = Nothing
Else
If t.left Is Nothing Then
Set FindMin = t
Else
Set FindMin = FindMin(t.left)
End If
End If
End Function
Public Function IsEmpty As Variant
Me.IsEmpty = root Is Nothing
End Function
Public Sub PrintTree
If Me.IsEmpty Then
Print "Empty tree"
Else
PrintRecursively root
End If
End Sub
Private Function FindMax(t As BinaryNode) As BinaryNode
If t Is Nothing Then
Set FindMax = Nothing
Else
If t.right Is Nothing Then
Set FindMax = t
Else
Set FindMax = FindMax(t.right)
End If
End If
End Function
Private Sub PrintRecursively(t As BinaryNode)
If Not t Is Nothing Then
PrintRecursively t.left
Print t.element
PrintRecursively t.right
End If
End Sub
Private Function Find(x As Variant, t As BinaryNode) As BinaryNode
If t Is Nothing Then
Set Find = Nothing
Else
If comp.Compare(x, t.element) < 0 Then
Set Find = Find(x, t.left)
Else
If comp.Compare(x, t.element) > 0 Then
Set Find = Find(x, t.right)
Else
Set Find = t
End If
End If
End If
End Function
Private Function AddRecursively(x As Variant, _
t As BinaryNode, found As Variant) As BinaryNode
If t Is Nothing Then
Set t = New BinaryNode(x, Nothing, Nothing)
Else
If comp.Compare(x, t.element) < 0 Then
Set t.left = AddRecursively(x, t.left, found)
Else
If comp.Compare(x, t.element) > 0 Then
Set t.right = AddRecursively(x, t.right, found)
Else
found = True
End If
End If
End If
Set AddRecursively = t
End Function
Private Function RemoveRecursively(x As Variant, t As BinaryNode, _
found As Variant) As BinaryNode
If t Is Nothing Then
Set RemoveRecursively = t
Exit Function
End If
If comp.Compare(x, t.element) < 0 Then
Set t.left = RemoveRecursively(x, t.left, found)
Else
If comp.Compare(x, t.element) > 0 Then
Set t.right = RemoveRecursively(x, t.right, found)
Else
found = True
If (Not t.left Is Nothing) And (Not t.right Is Nothing) Then
If RequiresSet(t.element) Then
Set t.element = FindMin(t.right).element
Else
t.element = FindMin(t.right).element
End If
Set t.right = RemoveRecursively(x, t.right, found)
Else
If Not t.left Is Nothing Then
Set t = t.left
Else
Set t = t.right
End If
End If
End If
End If
Set RemoveRecursively = t
End Function
Private Sub CollectElements(t As BinaryNode, resultList() As Variant,_
ndx As Long)
If Not t Is Nothing Then
CollectElements t.left, ResultList, ndx
Dim upper As Long
upper = Ubound(resultList)
If ndx > upper Then
Redim Preserve resultList((upper + 1) * 2 - 1)
End If
If RequiresSet(t.element) Then
Set resultList(ndx) = t.element
Else
resultList(ndx) = t.element
End If
ndx = ndx + 1
CollectElements t.right, resultList, ndx
End If
End Sub
End Class
Private Function RequiresSet(v As Variant) As Variant
Dim data_type As Integer
data_type = Datatype(v)
If data_type = 9 Or data_type = 34 Or data_type = 35 Then
RequiresSet = True
Else
RequiresSet = False
End If
End Function