Results 1 to 16 of 16

Thread: VB - Binary Search in array (array MUST be sorted)

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    VB - Binary Search in array (array MUST be sorted)

    Use the SearchArray function do to the search

    The array to search in must be sorted when you call this function, if it's not, use the code in this thread to sort first...
    http://vbforums.com/showthread.php?s=&threadid=231925

    VB Code:
    1. Public Function SearchArray(strArr() As String, StrToSearch As String, Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As Long
    2.     '
    3.     '  Made by Michael Ciurescu (CVMichael from vbforums.com)
    4.     '  Original thread: [url]http://www.vbforums.com/showthread.php?t=231934[/url]
    5.     '
    6.     Dim FComp As Long, LComp As Long
    7.    
    8.     FComp = StrComp(StrToSearch, strArr(LBound(strArr)), Compare)
    9.     LComp = StrComp(StrToSearch, strArr(UBound(strArr)), Compare)
    10.    
    11.     If FComp = -1 Then
    12.         SearchArray = LBound(strArr) - 1 ' less than first
    13.     ElseIf FComp = 0 Then
    14.         SearchArray = LBound(strArr)  ' equal to first
    15.     ElseIf LComp = 1 Then
    16.         SearchArray = UBound(strArr) + 1 ' larger than last
    17.     ElseIf LComp = 0 Then
    18.         SearchArray = UBound(strArr) ' equal to last
    19.     Else
    20.         ' in between first and last
    21.         SearchArray = ArrBinarySearch(strArr, StrToSearch, LBound(strArr), UBound(strArr), Compare)
    22.     End If
    23. End Function
    24.  
    25. Private Function ArrBinarySearch(strArr() As String, StrToSearch As String, ByVal First As Long, ByVal Last As Long, Optional ByVal Compare As VbCompareMethod) As Long
    26.     '
    27.     '  Made by Michael Ciurescu (CVMichael from vbforums.com)
    28.     '  Original thread: [url]http://www.vbforums.com/showthread.php?t=231934[/url]
    29.     '
    30.     Dim Mid As Long, StrC As Long
    31.    
    32.     If Abs(Last - First) <= 1 Then
    33.         ArrBinarySearch = First
    34.     Else
    35.         Mid = (First + Last) \ 2
    36.         StrC = StrComp(StrToSearch, strArr(Mid), Compare)
    37.        
    38.         Select Case StrC
    39.         Case -1
    40.             ArrBinarySearch = ArrBinarySearch(strArr, StrToSearch, First, Mid)
    41.         Case 0
    42.             ArrBinarySearch = Mid
    43.         Case 1
    44.             ArrBinarySearch = ArrBinarySearch(strArr, StrToSearch, Mid, Last)
    45.         End Select
    46.     End If
    47. End Function
    Last edited by CVMichael; Nov 30th, 2005 at 11:25 AM.

  2. #2
    New Member
    Join Date
    May 2005
    Posts
    6

    Lightbulb Re: VB - Binary Search in array (array MUST be sorted)

    Hmm.. i'm don't sure if it's only at my side, or if there's a general fail in your code.

    I've switched the Parameters for StrComp, and after that it works.

    Here's my code:
    VB Code:
    1. Option Explicit
    2. Option Base 1
    3.  
    4.  
    5. 'The array to search in MUST be sorted when you call this function !!!
    6.  
    7. Public Function SearchArray(ByRef sArray() As String, _
    8.                             ByRef sSearch As String, _
    9.                             Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As Long
    10.                            
    11.     Dim lLow    As Long
    12.     Dim lHigh   As Long
    13.     Dim sLow    As String
    14.     Dim sHigh   As String
    15.     Dim lFComp  As Long
    16.     Dim lLComp  As Long
    17.    
    18.     On Error Resume Next
    19.  
    20.     lLow = LBound(sArray)
    21.     lHigh = UBound(sArray)
    22.        
    23.     sLow = sArray(lLow)
    24.     sHigh = sArray(lHigh)
    25.    
    26.     lFComp = StrComp(sSearch, sLow, Compare)    'First
    27.     lLComp = StrComp(sSearch, sHigh, Compare)   'Last
    28.     'The StrComp function has the following return values:
    29.     '   -1      String1 sorts ahead of String2
    30.     '    0      String1 is equal to String2
    31.     '    1      String1 sorts after String2
    32.    
    33.     If lFComp <= 0 Then
    34.         SearchArray = lLow + lFComp     'less than first or equal to first
    35.     ElseIf lLComp >= 0 Then
    36.         SearchArray = lHigh + lLComp    'larger than last or equal to last
    37.     Else                                'in between first and last
    38.         SearchArray = ArrBinarySearch(sArray, sSearch, lLow, lHigh, Compare)
    39.     End If
    40. End Function
    41.  
    42. Private Function ArrBinarySearch(ByRef sArray() As String, _
    43.                                  ByRef sSearch As String, _
    44.                                  ByVal lFirst As Long, _
    45.                                  ByVal lLast As Long, _
    46.                                  Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As Long
    47.                                  
    48.     Dim lMid    As Long
    49.     Dim lStrC   As Long
    50.    
    51.     On Error Resume Next
    52.     If lFirst = lLast Then
    53.         ArrBinarySearch = lFirst
    54.     Else
    55.         lMid = (lFirst + lLast) \ 2
    56.         lStrC = StrComp(sSearch, sArray(lMid), Compare)
    57.        
    58.         Select Case lStrC
    59.             Case -1
    60.                 ArrBinarySearch = ArrBinarySearch(sArray, sSearch, lFirst, lMid)
    61.             Case 0
    62.                 ArrBinarySearch = lMid
    63.             Case 1
    64.                 ArrBinarySearch = ArrBinarySearch(sArray, sSearch, lMid, lLast)
    65.         End Select
    66.     End If
    67. End Function

    lg, :mike: freescale
    Last edited by freescale; May 19th, 2005 at 05:06 AM.

  3. #3

    Thread Starter
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: VB - Binary Search in array (array MUST be sorted)

    This is so weird !

    I'm sure 100% that I've tested this before I posted and it worked fine, why all of a sudden StrComp be reversed ???

    Damn Microsoft, why would they make changes like this ?

  4. #4
    New Member
    Join Date
    May 2005
    Posts
    6

    Question Re: VB - Binary Search in array (array MUST be sorted)

    So, related to the "bug" (I'm don't sure if it's one) i wrote about in http://vbforums.com/showpost.php?p=2019158&postcount=3 ,

    here's an example about what I mean.

    I am using the normal function ArrBinarySearch, but just with 2 lines added for debugging.

    VB Code:
    1. Private Function ArrBinarySearch(ByRef sArray() As String, _
    2.                                  ByRef sSearch As String, _
    3.                                  ByVal lFirst As Long, _
    4.                                  ByVal lLast As Long, _
    5.                                  Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As Long
    6.    
    7.     Dim lMid    As Long
    8.     Dim lStrC   As Long
    9.    
    10.     On Error Resume Next
    11.    
    12.     If lFirst = lLast Then
    13.         ArrBinarySearch = lFirst
    14.     Else
    15.        
    16.         lMid = (lFirst + lLast) \ 2         '<-- ###########
    17. [b]        MsgBox " "
    18.         Debug.Print "lFirst: " & lFirst & "  lLast: " & lLast & "  -->  lMid: " & lMid[/b]
    19.        
    20.         lStrC = StrComp(sSearch, sArray(lMid), Compare)
    21.        
    22.         Select Case lStrC
    23.             Case -1
    24.                 ArrBinarySearch = ArrBinarySearch(sArray(), sSearch, lFirst, lMid)
    25.             Case 0
    26.                 ArrBinarySearch = lMid
    27.             Case 1
    28.                 ArrBinarySearch = ArrBinarySearch(sArray(), sSearch, lMid, lLast)
    29.         End Select
    30.     End If

    This one is now called by the function SearchArray, because the element i'll search for, isn't the first or the last one.

    I'm calling SearchArray with
    VB Code:
    1. lResult = SearchArray(asMessageData(), sMessageData, vbTextCompare)

    where asMessageData is the Array i've stored some Text of Mails and sMessageData is an new Mail, where i want to check if this one already exists.

    This Array has an LBound of 1, and in this case, where it ends in an endless loop, the UBound of 4.
    Bevore, this also happend when my UBound was 35, and all other Values after 4 chr(0).

    Here's the Debug Output from the Line i've added above.
    Code:
    neu
    neu
    neu
    lFirst: 1  lLast: 4  -->  lMid: 2
    lFirst: 1  lLast: 2  -->  lMid: 1
    lFirst: 1  lLast: 2  -->  lMid: 1
    lFirst: 1  lLast: 2  -->  lMid: 1
    lFirst: 1  lLast: 2  -->  lMid: 1
    lFirst: 1  lLast: 2  -->  lMid: 1
    lFirst: 1  lLast: 2  -->  lMid: 1
    lFirst: 1  lLast: 2  -->  lMid: 1
    "Neu" means, i've got a new mail, this includes that the search function has passed without any errors.

    In the 4th case, as you see, it always returns to the value 1.
    Don't know how to fix this

    lg, freescale

  5. #5

    Thread Starter
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: VB - Binary Search in array (array MUST be sorted)

    You get an infinite loop when the search string is NOT in the array.
    Here's the fix, it simply returns the lower index of the closest match.
    VB Code:
    1. Private Function ArrBinarySearch(strArr() As String, StrToSearch As String, ByVal First As Long, ByVal Last As Long, Optional ByVal Compare As VbCompareMethod) As Long
    2.     Dim Mid As Long, StrC As Long
    3.    
    4.     [b]If Abs(Last - First) <= 1 Then[/b]
    5.         ArrBinarySearch = First
    6.     Else
    7.         Mid = (First + Last) \ 2
    8.         StrC = StrComp(StrToSearch, strArr(Mid), Compare)
    9.        
    10.         Select Case StrC
    11.         Case -1
    12.             ArrBinarySearch = ArrBinarySearch(strArr, StrToSearch, First, Mid)
    13.         Case 0
    14.             ArrBinarySearch = Mid
    15.         Case 1
    16.             ArrBinarySearch = ArrBinarySearch(strArr, StrToSearch, Mid, Last)
    17.         End Select
    18.     End If
    19. End Function
    (I also updated the main post in this thread with this change)

  6. #6
    New Member
    Join Date
    May 2005
    Posts
    6

    Re: VB - Binary Search in array (array MUST be sorted)

    Thank you!

    It's really very usefull

    ..and by the way.. one of the fastes i know

  7. #7
    Frenzied Member sciguyryan's Avatar
    Join Date
    Sep 2003
    Location
    Wales
    Posts
    1,763

    Re: VB - Binary Search in array (array MUST be sorted)

    Heres one I came up with, not shure how good it is compared with yours (Probably not as good ) but here it is in any case:

    VB Code:
    1. Function BinarySearch(strArray() As String, strSearch As String) As Long
    2.     Dim lngIndex As Long
    3.     Dim lngFirst As Long
    4.     Dim lngLast As Long
    5.     Dim lngMiddle As Long
    6.     Dim bolInverseOrder As Boolean
    7.     lngFirst = LBound(strArray)
    8.     lngLast = UBound(strArray)
    9.     bolInverseOrder = (strArray(lngFirst) > strArray(lngLast))
    10.     BinarySearch = lngFirst - 1
    11.     Do
    12.         lngMiddle = (lngFirst + lngLast) \ 2
    13.         If strArray(lngMiddle) = strSearch Then
    14.             BinarySearch = lngMiddle
    15.             Exit Do
    16.         ElseIf ((strArray(lngMiddle) < strSearch) Xor bolInverseOrder) Then
    17.             lngFirst = lngMiddle + 1
    18.         Else
    19.             lngLast = lngMiddle - 1
    20.         End If
    21.     Loop Until lngFirst > lngLast
    22. End Function

    Cheers,

    RyanJ
    My Blog.

    Ryan Jones.

  8. #8

    Thread Starter
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: VB - Binary Search in array (array MUST be sorted)

    It seems that your code is better...
    I used the folloing test:
    VB Code:
    1. Option Explicit
    2.  
    3. Private MikeLoops As Long, MikeLoopsTotal As Long
    4. Private SciguyryanLoops As Long, SciguyryanLoopsTotal As Long
    5.  
    6. Private Sub Form_Load()
    7.     Dim Arr(25) As String, K As Long
    8.    
    9.     For K = 0 To UBound(Arr)
    10.         Arr(K) = Chr(65 + K)
    11.     Next K
    12.    
    13.     For K = 0 To UBound(Arr)
    14.         MikeLoops = 0
    15.         SciguyryanLoops = 0
    16.        
    17.         Debug.Print Arr(K), MikeLoops & " - " & SearchArray(Arr, Arr(K)), SciguyryanLoops & " - " & BinarySearch(Arr, Arr(K))
    18.        
    19.         MikeLoopsTotal = MikeLoopsTotal + MikeLoops
    20.         SciguyryanLoopsTotal = SciguyryanLoopsTotal + SciguyryanLoops
    21.     Next K
    22.    
    23.     Debug.Print "Mike Loops Total: " & MikeLoopsTotal, "Sciguyryan Loops Total: " & SciguyryanLoopsTotal
    24. End Sub
    25.  
    26. Function BinarySearch(strArray() As String, strSearch As String) As Long
    27.     Dim lngIndex As Long
    28.     Dim lngFirst As Long
    29.     Dim lngLast As Long
    30.     Dim lngMiddle As Long
    31.     Dim bolInverseOrder As Boolean
    32.    
    33.     lngFirst = LBound(strArray)
    34.     lngLast = UBound(strArray)
    35.    
    36.     bolInverseOrder = (strArray(lngFirst) > strArray(lngLast))
    37.     BinarySearch = lngFirst - 1
    38.    
    39.     Do
    40.         SciguyryanLoops = SciguyryanLoops + 1
    41.        
    42.         lngMiddle = (lngFirst + lngLast) \ 2
    43.        
    44.         If strArray(lngMiddle) = strSearch Then
    45.             BinarySearch = lngMiddle
    46.             Exit Do
    47.         ElseIf ((strArray(lngMiddle) < strSearch) Xor bolInverseOrder) Then
    48.             lngFirst = lngMiddle + 1
    49.         Else
    50.             lngLast = lngMiddle - 1
    51.         End If
    52.     Loop Until lngFirst > lngLast
    53. End Function
    54.  
    55. Public Function SearchArray(strArr() As String, StrToSearch As String, Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As Long
    56.     Dim FComp As Long, LComp As Long
    57.    
    58.     MikeLoops = MikeLoops + 1
    59.    
    60.     FComp = StrComp(StrToSearch, strArr(LBound(strArr)), Compare)
    61.     LComp = StrComp(StrToSearch, strArr(UBound(strArr)), Compare)
    62.    
    63.     If FComp = -1 Then
    64.         SearchArray = LBound(strArr) - 1 ' less than first
    65.     ElseIf FComp = 0 Then
    66.         SearchArray = LBound(strArr)  ' equal to first
    67.     ElseIf LComp = 1 Then
    68.         SearchArray = UBound(strArr) + 1 ' larger than last
    69.     ElseIf LComp = 0 Then
    70.         SearchArray = UBound(strArr) ' equal to last
    71.     Else
    72.         ' in between first and last
    73.         SearchArray = ArrBinarySearch(strArr, StrToSearch, LBound(strArr), UBound(strArr), Compare)
    74.     End If
    75. End Function
    76.  
    77. Private Function ArrBinarySearch(strArr() As String, StrToSearch As String, ByVal First As Long, ByVal Last As Long, Optional ByVal Compare As VbCompareMethod) As Long
    78.     Dim Mid As Long, StrC As Long
    79.    
    80.     MikeLoops = MikeLoops + 1
    81.    
    82.     If Abs(Last - First) <= 1 Then
    83.         ArrBinarySearch = First
    84.     Else
    85.         Mid = (First + Last) \ 2
    86.         StrC = StrComp(StrToSearch, strArr(Mid), Compare)
    87.        
    88.         Select Case StrC
    89.         Case -1
    90.             ArrBinarySearch = ArrBinarySearch(strArr, StrToSearch, First, Mid)
    91.         Case 0
    92.             ArrBinarySearch = Mid
    93.         Case 1
    94.             ArrBinarySearch = ArrBinarySearch(strArr, StrToSearch, Mid, Last)
    95.         End Select
    96.     End If
    97. End Function
    And the result:
    Code:
    A             1 - 0         4 - 0
    B             5 - 1         5 - 1
    C             6 - 2         3 - 2
    D             4 - 3         4 - 3
    E             5 - 4         5 - 4
    F             6 - 5         2 - 5
    G             3 - 6         4 - 6
    H             5 - 7         5 - 7
    I             6 - 8         3 - 8
    J             4 - 9         5 - 9
    K             5 - 10        4 - 10
    L             6 - 11        5 - 11
    M             2 - 12        1 - 12
    N             5 - 13        4 - 13
    O             6 - 14        5 - 14
    P             4 - 15        3 - 15
    Q             5 - 16        5 - 16
    R             6 - 17        4 - 17
    S             3 - 18        5 - 18
    T             5 - 19        2 - 19
    U             6 - 20        4 - 20
    V             4 - 21        5 - 21
    W             6 - 22        3 - 22
    X             5 - 23        5 - 23
    Y             6 - 24        4 - 24
    Z             1 - 25        5 - 25
    Mike Loops Total: 120       Sciguyryan Loops Total: 104

  9. #9
    Frenzied Member sciguyryan's Avatar
    Join Date
    Sep 2003
    Location
    Wales
    Posts
    1,763

    Re: VB - Binary Search in array (array MUST be sorted)

    Hmm... Thats interesting....

    Well, I will still be using yours because yours is shorter and I prefer short code to long ones

    I wonder if anoyne else has an even faster way to do this?

    Cheers,

    RyanJ
    My Blog.

    Ryan Jones.

  10. #10

    Thread Starter
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: VB - Binary Search in array (array MUST be sorted)

    Time test:
    VB Code:
    1. Option Explicit
    2.  
    3. Private Declare Function GetTickCount Lib "kernel32" () As Long
    4.  
    5. Private Sub Form_Load()
    6.     Dim Arr(25) As String, K As Long, Q As Long, Dummy As Long
    7.     Dim StartTime As Long
    8.    
    9.     For K = 0 To UBound(Arr)
    10.         Arr(K) = Chr(65 + K)
    11.     Next K
    12.    
    13.     StartTime = GetTickCount
    14.    
    15.     For Q = 1 To 10000
    16.         For K = 0 To UBound(Arr)
    17.             Dummy = SearchArray(Arr, Arr(K))
    18.         Next K
    19.     Next Q
    20.    
    21.     Debug.Print "Mike time: " & GetTickCount - StartTime
    22.    
    23.     StartTime = GetTickCount
    24.    
    25.     For Q = 1 To 10000
    26.         For K = 0 To UBound(Arr)
    27.             Dummy = BinarySearch(Arr, Arr(K))
    28.         Next K
    29.     Next Q
    30.    
    31.     Debug.Print "Sciguyryan time: " & GetTickCount - StartTime
    32. End Sub

    Result:
    Mike time: 1422
    Sciguyryan time: 953

    Yours is better again....

  11. #11
    Member
    Join Date
    Aug 2010
    Posts
    48

    Re: VB - Binary Search in array (array MUST be sorted)

    Please how do i call binary search function to search for a record in my database and display it?
    How to call my database to work with the algorithm in the function. Please some help.

  12. #12

    Thread Starter
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: VB - Binary Search in array (array MUST be sorted)

    You don't need binary search if your using a database.

    Next time, make a thread in the database forum, and ask your question there.

  13. #13
    Member
    Join Date
    Aug 2010
    Posts
    48

    Re: VB - Binary Search in array (array MUST be sorted)

    sorry for this ok, just need a quick help please. i am making a thread now in the database.

  14. #14
    Hyperactive Member capsulecorpjx's Avatar
    Join Date
    May 2005
    Location
    Renton, WA
    Posts
    288

    Re: VB - Binary Search in array (array MUST be sorted)

    Quote Originally Posted by sciguyryan View Post
    Heres one I came up with, not shure how good it is compared with yours (Probably not as good ) but here it is in any case:

    VB Code:
    1. Function BinarySearch(strArray() As String, strSearch As String) As Long
    2.     Dim lngIndex As Long
    3.     Dim lngFirst As Long
    4.     Dim lngLast As Long
    5.     Dim lngMiddle As Long
    6.     Dim bolInverseOrder As Boolean
    7.     lngFirst = LBound(strArray)
    8.     lngLast = UBound(strArray)
    9.     bolInverseOrder = (strArray(lngFirst) > strArray(lngLast))
    10.     BinarySearch = lngFirst - 1
    11.     Do
    12.         lngMiddle = (lngFirst + lngLast) \ 2
    13.         If strArray(lngMiddle) = strSearch Then
    14.             BinarySearch = lngMiddle
    15.             Exit Do
    16.         ElseIf ((strArray(lngMiddle) < strSearch) Xor bolInverseOrder) Then
    17.             lngFirst = lngMiddle + 1
    18.         Else
    19.             lngLast = lngMiddle - 1
    20.         End If
    21.     Loop Until lngFirst > lngLast
    22. End Function

    Cheers,

    RyanJ
    I don't think this code will work without a "Floor" function.

    When calculating the middle with "Long" datatypes, you might get .5 (5.5, 6.5, etc..).

    When trying to access an array with a .5, you'll get a blank string:

    For example
    strArray(3.5) will return a nullstring.
    "I like to run on treadmills, because at least I know I'm getting nowhere."
    - Me

  15. #15

    Thread Starter
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: VB - Binary Search in array (array MUST be sorted)

    Well, both of our codes use the integer division, so I don't see how you get decimals.

    If you look, we are using "\" (integer division) instead of "/".

  16. #16
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: VB - Binary Search in array (array MUST be sorted)

    The reason the non-recursive one is faster is because he eliminates the just-checked value, since it has already been checked. This means his remaining pool of numbers to check shrinks by 1 every iteration compared to yours.

    To generate the same performance -- though yours will probably still be trivially slower due to recursion -- change your recursive calls to:
    Code:
                ArrBinarySearch = ArrBinarySearch(strArr, StrToSearch, First, Mid - 1)
            Case 0
                ArrBinarySearch = Mid
            Case 1
                ArrBinarySearch = ArrBinarySearch(strArr, StrToSearch, Mid + 1, Last)
    I've been using binary searches a lot lately, and have finally realized that my old implementation for finding the first match is quite inefficient. Maybe someday I'll fix it.

    Yours does not find the first match, btw; it simply stops looking whenever it finds any match. For example, if you have 100 identical items in an array your binary search will return the 50th item. This is usually undesirable.
    Last edited by Ellis Dee; Nov 23rd, 2010 at 04:27 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width