Arrays 对从ADO记录集创建的变量数组使用二进制搜索
我使用VB6(是的,我知道)获取ADO记录集(超过650000条记录),并将该记录集加载到一个变量数组中。然后,我尝试使用我在网上找到的二进制搜索函数搜索数组,查看其中是否存在指定的字符串值。当我调用二进制搜索函数时,收到错误消息“下标超出范围”。知道我做错了什么吗Arrays 对从ADO记录集创建的变量数组使用二进制搜索,arrays,vb6,ado,binary-search,Arrays,Vb6,Ado,Binary Search,我使用VB6(是的,我知道)获取ADO记录集(超过650000条记录),并将该记录集加载到一个变量数组中。然后,我尝试使用我在网上找到的二进制搜索函数搜索数组,查看其中是否存在指定的字符串值。当我调用二进制搜索函数时,收到错误消息“下标超出范围”。知道我做错了什么吗 Dim arrItems() As Variant 'gXRst and gXCon are global variables declared elsewhere. They are not the problem here. W
Dim arrItems() As Variant
'gXRst and gXCon are global variables declared elsewhere. They are not the problem here.
With gXRst
.CursorLocation = adUseClient
.CursorType = adOpenKeyset
.LockType = adLockReadOnly
.Open "SELECT item_cd FROM xmsalinv ORDER BY item_cd ASC", gXCon
End With
arrItems = gXRst.GetRows(gXRst.RecordCount)
gXRst.Close
MsgBox BinarySearch(arrItems(), "491588S")
Function BinarySearch(arr As Variant, search As String, _
Optional lastEl As Variant) As Long
Dim index As Long
Dim first As Long
Dim last As Long
Dim middle As Long
Dim inverseOrder As Boolean
' account for optional arguments
If IsMissing(lastEl) Then lastEl = UBound(arr)
first = LBound(arr)
last = lastEl
'Error message occurring on next line. Error 9, subscript out of range.
' deduct direction of sorting
inverseOrder = (arr(first) > arr(last))
' assume searches failed
BinarySearch = first - 1
Do
middle = (first + last) \ 2
If arr(middle) = search Then
BinarySearch = middle
Exit Do
ElseIf ((arr(middle) < search) Xor inverseOrder) Then
first = middle + 1
Else
last = middle - 1
End If
Loop Until first > last
End Function
items()作为变量
'gXRst和gXCon是在别处声明的全局变量。他们不是这里的问题。
用gXRst
.CursorLocation=adUseClient
.CursorType=adOpenKeyset
.LockType=adLockReadOnly
.打开gXCon“按项目cd ASC从xmsalinv订单中选择项目cd”
以
arrItems=gXRst.GetRows(gXRst.RecordCount)
gXRst,关闭
MsgBox二进制搜索(arrItems(),“491588S”)
函数BinarySearch(arr作为变量,搜索作为字符串_
可选拉斯泰尔(作为变型)长度相同
暗指数与长指数相同
一开始就黯然失色
持续时间一样长
暗淡的中等长度
布尔型弱逆序
'用于可选参数的帐户
如果IsMissing(lastEl),则lastEl=UBound(arr)
第一个=LBound(arr)
last=lastEl
'下一行出现错误消息。错误9,下标超出范围。
'扣除排序方向
逆序=(arr(第一个)>arr(最后一个))
'假设搜索失败
BinarySearch=first-1
做
中间=(第一个+最后一个)\2
如果arr(中间)=搜索,则
BinarySearch=middle
退出Do
ElseIf((arr(middle)最后一个
端函数
获取行,但二进制搜索例程需要1D数组
为什么不直接使用记录集中的内置对象呢?它比手工翻滚的二进制搜索更快,也更容易
gXRst.MoveFirst
gXRst.Find("item_cd='491588S'")
MsgBox gXRst.Fields("item_cd").Value
在野外有很多垃圾手工编码的排序,很多都有细微的错误,大多数是“玩具”排序,排序的是一维数组。很多都是“速度怪胎”程序员的产物,他们很少创建真正的程序,但喜欢修补程序。注意在许多二进制搜索例程中也会出现“offbyone”错误(例如,不能处理元素的偶数或奇数) 你已经“花掉”资源建立了一个记录集,所以考虑用TWIME使用它。 使用优化: 您可以通过使用客户端游标、正确的游标类型和在所使用的键上创建索引(优化动态属性)来提高gXRst.Find的性能: 首先查找:
gXRst.Find "item_cd = '4915885'", , adSearchForward, adBookMarkFirst
查找下一个:
gXRst.Find "item_cd = '4915885'", 1, adSearchForward, adBookMarkCurrent
最后查找:
gXRst.Find "item_cd = '4915885'", , adSearchBackward, adBookMarkLast
当然要注意,在调用Find之前必须设置当前行位置。如有疑问,请使用MoveFirst、MoveLast等,或使用书签值从first/last开始(默认为adBookMarkCurrent)
摘自Rob Macdonald的PowerPoint演示文稿(约1999年):
我已经在使用find方法,我正在寻找加快速度的方法。我假设进行二进制搜索会更快。作为一个附带问题,大多数数组搜索例程是否假设为一列1D数组?当我看到其他人在线编写的搜索数组例程时,我有些困惑。
gXRst.Find "item_cd = '4915885'", , adSearchBackward, adBookMarkLast
Data Structures Compared
Figures below are based on a 5000 row, 4 column data structure.
* Times are normalised on Variant Array performance
* Array sorting is 400 times slower than iteration
Variant Array Recordset Indexed Recordset Collection
----------- ------------- --------- ----------------- -----------
Iterate 100 2,120 2,160 120
Find 1 (1) 100 308 2.6 0.9/212 (2)
Find n (1) 100 422 17 393
Sort (1) 100 3.2 3.0 7,076
(1) timings include iterating through the results
(2) the faster time is achieved if searching by collection key is possible