Arrays
Searching
When working with arrays, it is often necessary to perform a search or "lookup" to determine whether an array contains a value that matches a certain key value. For example, the data from a file or database table will typically contain a "key" field (such as a code), along with corresponding data fields (such as a description). It is often convenient to work with such data by first loading it into a structure array in an initial routine, and then later pulling data from the array given a key value to search on.
Three versions of a sample project to look up a state abbreviation and return the corresponding state name will now be presented. The first version demonstrates how to perform a serial search (also called a linear search) on an array; the second and third demonstrate how to perform a binary search.
These projects will process a sequential file of state abbreviations and corresponding state names called STATES.DAT, with the following contents:
"AK","ALASKA"
"AL","ALABAMA"
.
.
.
"WV","WEST VIRGINIA"
"WY","WYOMING"
Serial Search Example
The program code and corresponding output is shown below:
VB Code: |
Screen-shot of run: |
Module Module1
Private Structure StateRecord Dim StateAbbrev As String Dim StateName As String End Structure
Private maudtStateRecord() As StateRecord
Public Sub Main()
Dim strTestAbbrev As String Dim strTestName As String
LoadStateData()
Console.Write("Enter a state abbreviation (or just press Enter to quit): ") strTestAbbrev = UCase(Console.ReadLine())
Do Until strTestAbbrev = "" strTestName = GetStateName(strTestAbbrev)
If strTestName = "" Then Console.WriteLine("No state name found for '" & strTestAbbrev & "'.") Else Console.WriteLine("'" & strTestAbbrev & "' is the abbreviation for '" _ & strTestName & "'.") End If Console.WriteLine() Console.Write("Enter a state abbreviation (or just press Enter to quit): ") strTestAbbrev = UCase(Console.ReadLine()) Loop
End Sub
Private Sub LoadStateData()
Dim intStateFileNbr As Integer Dim intStateUB As Integer
intStateFileNbr = FreeFile() intStateUB = -1
FileOpen(intStateFileNbr, _ My.Application.Info.DirectoryPath & "\STATES.DAT", _ OpenMode.Input)
Do Until EOF(intStateFileNbr) intStateUB += 1 ReDim Preserve maudtStateRecord(intStateUB) With maudtStateRecord(intStateUB) Input(intStateFileNbr, .StateAbbrev) Input(intStateFileNbr, .StateName) End With Loop
FileClose(intStateFileNbr)
End Sub
Private Function GetStateName(ByRef pstrTestAbbrev As String) As String
Dim intX As Integer
For intX = 0 To UBound(maudtStateRecord) If pstrTestAbbrev = maudtStateRecord(intX).StateAbbrev Then Return maudtStateRecord(intX).StateName End If Next
' if we get here, the state was not found ... Return ""
End Function
End Module |
|
The technique used here is called a serial search, because the StateAbbrev elements of the maudtStateRecord structure array are compared one by one to the state abbreviation being looked for (pstrTestAbbrev) until either a match is found or all elements of the array are examined without finding a match. If a match on the state abbreviation is found, the corresponding state name is returned.
Download the VB project code for the example above here.
Binary Search Examples
The serial search is fine for small or unsorted arrays, but for larger arrays, serial searching is inefficient. If an array is sorted (and that is important – in the case of the state data file we are working with, the records are sorted by state abbreviation, which is desirable), the very efficient technique of binary searching can be used. In a binary search, the element at the middle of the array is checked first. If a match is found, the search ends. Otherwise, the program determines whether the array argument needed is in the upper half of the array or the lower half. The half of the array containing the array argument is again halved and the search continues as before. The term "binary" here refers to this process of dividing by two.
The basic algorithm for a binary search is shown (in pseudocode) below:
Set MIN_INDEX = LBound(Array)
Set MAX_INDEX = UBound(Array)
Do While MIN_INDEX <= MAX_INDEX
Set MIDDLE_INDEX = INT((MIN_INDEX + MAX_INDEX) / 2)
If SEARCH_ITEM < ARRAY_ITEM(MIDDLE_INDEX) Then
Set MAX_INDEX = MIDDLE_INDEX – 1
ElseIf SEARCH_ITEM > ARRAY_ITEM(MIDDLE_INDEX) Then
Set MIN_INDEX = MIDDLE_INDEX + 1
Else
' Item has been found at MIDDLE_INDEX of array
Exit Do
End If
Loop
Binary Search Example 1
In the next programming example, the state lookup process has been modified to implement the binary search:
VB Code: |
Screen-shot of run: |
Module Module1
Private Structure StateRecord Dim StateAbbrev As String Dim StateName As String End Structure
Private maudtStateRecord() As StateRecord
Public Sub Main()
Dim strTestAbbrev As String Dim strTestName As String
LoadStateData()
Console.Write("Enter a state abbreviation (or just press Enter to quit): ") strTestAbbrev = UCase(Console.ReadLine())
Do Until strTestAbbrev = "" strTestName = GetStateName(strTestAbbrev)
If strTestName = "" Then Console.WriteLine("No state name found for '" & strTestAbbrev & "'.") Else Console.WriteLine("'" & strTestAbbrev & "' is the abbreviation for '" _ & strTestName & "'.") End If Console.WriteLine() Console.Write("Enter a state abbreviation (or just press Enter to quit): ") strTestAbbrev = UCase(Console.ReadLine()) Loop
End Sub
Private Sub LoadStateData()
Dim intStateFileNbr As Integer Dim intStateUB As Integer
intStateFileNbr = FreeFile() intStateUB = -1
FileOpen(intStateFileNbr, _ My.Application.Info.DirectoryPath & "\STATES.DAT", _ OpenMode.Input)
Do Until EOF(intStateFileNbr) intStateUB += 1 ReDim Preserve maudtStateRecord(intStateUB) With maudtStateRecord(intStateUB) Input(intStateFileNbr, .StateAbbrev) Input(intStateFileNbr, .StateName) End With Loop
FileClose(intStateFileNbr)
End Sub
Private Function GetStateName(ByVal pstrTestAbbrev As String) As String
Dim intMinIndex As Integer Dim intMaxIndex As Integer Dim intMidIndex As Integer
intMinIndex = 0 intMaxIndex = UBound(maudtStateRecord)
Do While intMinIndex <= intMaxIndex intMidIndex = Int((intMinIndex + intMaxIndex) / 2) If pstrTestAbbrev < maudtStateRecord(intMidIndex).StateAbbrev Then intMaxIndex = intMidIndex - 1 ElseIf pstrTestAbbrev > maudtStateRecord(intMidIndex).StateAbbrev Then intMinIndex = intMidIndex + 1 Else ' we have a match Return maudtStateRecord(intMidIndex).StateName End If Loop
' if we get here, the state was not found ... Return ""
End Function
End Module |
|
Download the VB project code for the example above here.
Binary Search Example 2
VB.Net introduced a number of methods that operate on arrays, one being BinarySearch, which implements the algorithm discussed above. The BinarySearch method operates on a one-dimensional array. The general syntax is:
Position = Array.BinarySearch(Array, ValueToFind)
where Array is the one-dimensional array to search, ValueToFind is the value that you are looking for, and Position is the index in the array where the item was found. If the item is not found, the value of Position will be a negative number.
Say we had an array of names as follows (note that the names are sorted):
Dim astrNames() As String = {"Archie", "Betty", "Charlie", "David", "Esther", "Frank", "George", "Heather", "Imogene", "Jack"}
Assuming you had a variable called intPosX defined As Integer, the following statements would produce the following results:
intPosX = Array.BinarySearch(astrNames, "Heather") ' intPosX would be 7
intPosX = Array.BinarySearch(astrNames, "Archie") ' intPosX would be 0
intPosX = Array.BinarySearch(astrNames, "Betty") ' intPosX would be 1
intPosX = Array.BinarySearch(astrNames, "Archie") ' intPosX would be a negative number, indicating the name was not found
To use the BinarySearch method in our state name lookup example, we would need to modify the way we are storing the state abbreviations and their corresponding state names – because the BinarySearch method operates on a one-dimensional array, not a structure. A way to do it would be to store the data into two separate arrays: one for the state abbreviations, the other for the state names. The BinarySearch would operate on the state abbreviation array, and the resulting index for the found abbreviation would also be the index for the corresponding state name in the state name array. The example below demonstrates this:
VB Code: |
Screen-shot of run: |
Module Module1
Private mastrStateAbbrev() As String Private mastrStateName() As String
Public Sub Main()
Dim strTestAbbrev As String Dim strTestName As String
LoadStateData()
Console.Write("Enter a state abbreviation (or just press Enter to quit): ") strTestAbbrev = UCase(Console.ReadLine())
Do Until strTestAbbrev = "" strTestName = GetStateName(strTestAbbrev)
If strTestName = "" Then Console.WriteLine("No state name found for '" & strTestAbbrev & "'.") Else Console.WriteLine("'" & strTestAbbrev & "' is the abbreviation for '" _ & strTestName & "'.") End If Console.WriteLine() Console.Write("Enter a state abbreviation (or just press Enter to quit): ") strTestAbbrev = UCase(Console.ReadLine()) Loop
End Sub
Private Sub LoadStateData()
Dim intStateFileNbr As Integer Dim intStateUB As Integer
intStateFileNbr = FreeFile() intStateUB = -1
FileOpen(intStateFileNbr, _ My.Application.Info.DirectoryPath & "\STATES.DAT", _ OpenMode.Input)
Do Until EOF(intStateFileNbr) intStateUB += 1 ReDim Preserve mastrStateAbbrev(intStateUB) ReDim Preserve mastrStateName(intStateUB) Input(intStateFileNbr, mastrStateAbbrev(intStateUB)) Input(intStateFileNbr, mastrStateName(intStateUB)) Loop
FileClose(intStateFileNbr)
End Sub
Private Function GetStateName(ByVal pstrTestAbbrev As String) As String
Dim intPosition As Integer
intPosition = Array.BinarySearch(mastrStateAbbrev, pstrTestAbbrev)
If intPosition < 0 Then Return "" Else Return mastrStateName(intPosition) End If
End Function
End Module |
|
Download the VB project code for the example above here.