Arrays 对从ADO记录集创建的变量数组使用二进制搜索

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

我使用VB6(是的,我知道)获取ADO记录集(超过650000条记录),并将该记录集加载到一个变量数组中。然后,我尝试使用我在网上找到的二进制搜索函数搜索数组,查看其中是否存在指定的字符串值。当我调用二进制搜索函数时,收到错误消息“下标超出范围”。知道我做错了什么吗

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