二分法实现的符号表
' 二分查找的符号表
' 隔离索引,从1开始,数组操作从0开始
' 这种设计隔离数组操作,只是为了方便理解,如果实际使用,可以修改为 从0开始,能节省不少操作。
Private keys()
Private values()
Private n As Long
' 暂时省略辅助的增加和缩减,如有需要,参照以前的博客
' 基本的符号表api
Private Sub class_initialize()
' 省略增加,适当加大
ReDim keys(100)
ReDim values(100)
End Sub
' 把值加入符号表中,如果值为空,就删除主键
Sub putValue(key As Variant, val As Variant)
Dim index As Long
Dim temp As Variant
index = rank(key)
Dim i As Long
' 需要考虑到相等的情况
' 终究是不太明白为什么index会大于n?哪种情况?
If index <= n And index > 0 Then
If getKeyByIndex(index) = key Then
setValueByIndex index, val
Exit Sub
End If
End If
For i = n + 1 To index + 2 Step -1
setKeyByIndex i, getKeyByIndex(i - 1)
setValueByIndex i, getValueByIndex(i - 1)
Next
setKeyByIndex index + 1, key
setValueByIndex index + 1, val
n = n + 1
End Sub
' 为了索引和数量保持对应,隔离数组操作
Function less(i As Variant, j As Variant) As Boolean
less = i < j
End Function
Function greator(i As Variant, j As Variant) As Boolean
greator = i > j
End Function
Function getKeyByIndex(i As Long) As Variant
getKeyByIndex = keys(i - 1)
End Function
Function getValueByIndex(i As Long) As Variant
getValueByIndex = values(i - 1)
End Function
Sub setKeyByIndex(i As Long, key As Variant)
keys(i - 1) = key
End Sub
Sub setValueByIndex(i As Long, value As Variant)
values(i - 1) = value
End Sub
' 获取键的值,如果键为空,就返回空
Function getValue(key As Variant) As Variant
Dim index As Long
If isEmpty() Then getValue = Null: Exit Function
index = rank(key)
If index <= n Then
If getKeyByIndex(index) = key Then
getValue = getValueByIndex(index)
Exit Function
End If
End If
getValue = Null
End Function
' 从表中删除主键
Sub delete(key As Variant)
Dim index As Long
End Sub
' 主键是否存在于符号表中
Function contains(key As Variant) As Boolean
Dim index As Long
index = rank(key)
If index <= n Then
If getKeyByIndex(index) = key Then contains = True: Exit Function
End If
contains = False
End Function
' 是否为空
Function isEmpty() As Boolean
isEmpty = n = 0
End Function
' 最小的主键
Function min() As Variant
min = getKeyByIndex(1)
End Function
' 最大的主键
Function max() As Variant
max = getKeyByIndex(n)
End Function
' 小于等于key的最大键
Function floor(key As Variant) As Variant
Dim index As Long
index = rank(key)
floor = getKeyByIndex(index)
End Function
' 大于等于key的最小键
Function ceiling(key As Variant) As Variant
Dim index As Long
index = rank(key)
ceiling = getKeyByIndex(index + 1)
End Function
' 小于key的数量
Function rank(key As Variant) As Long
Dim low As Long
Dim high As Long
low = 1
high = n
rank = doRank(key, low, high)
End Function
' 实施二分查找,这种方式更加直观
Private Function doRank(key As Variant, low As Long, high As Long) As Long
Dim mid As Long
Dim midKey As Variant
' high比low小,说明没有匹配的结果,只能选择合适的结果返回?high还是low是合适结果?
' 主要看返回,这里是以1为开始索引,所以返回的位置,刚好是等于或者小于key的最大值的个数,
' 当high < low 的时候,说明数组开始越界,有可能是high越界,也有可能是low越界,
' 这取决于上层是大于还是小于key。
' 如果上层是比key更大,即less(key,midKey)成立,准确位置就是low,
' 而因为比key大,所以需要-1才是比key小的位置,位置和个数是对应的。取low-1,即high
' 如果上层比key小,即greator(key,midKey)成立,准确位置就是high,
' 而因为比key小,所以这个位置刚好就是需要返回的位置,即个数,包括0。
' 而如果索引是从0开始,返回的是个数,也从0开始,返回偏大的索引刚好就是个数,因为索引+1 = 个数
' high + 1 = low ,所以返回low
If high < low Then doRank = high: Exit Function
' 中间位置划分偏向左边,即左边更多
mid = Int((high + low) / 2)
midKey = getKeyByIndex(mid)
If less(key, midKey) Then
doRank = doRank(key, low, mid - 1)
Exit Function
ElseIf greator(key, midKey) Then
doRank = doRank(key, mid + 1, high)
Exit Function
End If
doRank = mid
End Function
' 排名为key的键
Function find(k As Long) As Variant
find = getKeyByIndex(k)
End Function
' 删除最小的键
Sub deleteMin()
End Sub
' 删除最大的键
Sub deletMax()
End Sub
' 数量
Function size() As Integer
size = n
End Function
' 键之间的数量
Function sizeRange(low As Variant, high As Variant)
End Function
' 键之间的所有主键
Function keysRange(low As Variant, high As Variant) As Collection
End Function
' 所有主键
Function keysAll() As Collection
End Function