Arrays in Visual Basic

By Herbert J. Bernstein

© Copyright 1999 Herbert J. Bernstein

 

Arrays are a means of giving multiple data items a single name. Individual data items are identified by combining the name of the array one or more numeric indices. If there is one index, it indicates which item in a single row of array elements is desired. If there are two indices, they indicate by row and column which element is desired. More indices are allowed.

There are two ways to declare storage for an arrays in Visual Basic:


     Dim variable( ilo TO ihi ) As type
     Dim variable( ilo TO ihi, jlo TO jhi ) As type
     Dim variable( ilo TO ihi, jlo TO jhi, klo TO khi ) As type
     ...

is used to declare an array when the dimensions are known constants. If the lower index for any dimension is zero, it may be omitted.


     ReDim variable( ilo TO ihi ) As type
     ReDim variable( ilo TO ihi, jlo TO jhi ) As type
     ReDim variable( ilo TO ihi, jlo TO jhi, klo TO khi ) As type
     ...

is used to declare an array within a procedure when any of the dimensions are computed from variables or are different from the original declaration. The number of indices must be the same as in the original declaration.

If an array is to be known to all subprocedures, a declaration


     Dim variable() As type
should appear in the (General) section of the code.

When passing an array as an argument


     variable()
should appear in the list of actual arguments in the call and

     variable() As type
should appear in the list of formal parameters in the subprocedure or function definition.

The following code uses an array to sort names with a simple bubble sort:


Rem Sample of a Bubble Sort
Rem H. J. Bernstein, 7 November 1999

Rem Requires a Form with an output text box Text1
Rem                      an input text box Text2
Rem                        with properties
Rem                          ScrollBars 2 (Vertical)
Rem                          Multiline True
Rem                      an enter button EnterButton
Rem                      a sort button SortButton


Dim Names$(1 To 2000)
Dim NameCount As Integer

Private Sub EnterButton_Click()
  NameCount = NameCount + 1
  Names(NameCount) = Text2.Text
  Text1.Text = Text1.Text & Text2.Text & Chr(13) & Chr(10)
  Text2.Text = ""
End Sub

Private Sub Form_Load()
  NameCount = 0
  Text1.Text = ""
  Text2.Text = ""
End Sub

Private Sub SortButton_Click()
  Dim Done As Integer
  Dim Icount As Integer
  Dim Temp As String

  Do
  Done = 1
  For Icount = 2 To NameCount
    If (UCase(Names(Icount - 1)) > UCase(Names(Icount))) Then
      Temp = Names(Icount)
      Names(Icount) = Names(Icount - 1)
      Names(Icount - 1) = Temp
      Done = 0
    End If
  Next Icount
  Loop Until (Done = 1)
  
  Text1.Text = ""
  For Icount = 1 To NameCount
    Text1.Text = Text1.Text & Names(Icount) & Chr(13) & Chr(10)
  Next Icount
  
End Sub

This can be redone using a Shell sort:


Rem Sample of a Shell Sort
Rem H. J. Bernstein, 7 November 1999

Rem Requires a Form with an output text box Text1
Rem                      an input text box Text2
Rem                        with properties
Rem                          ScrollBars 2 (Vertical)
Rem                          Multiline True
Rem                      an enter button EnterButton
Rem                      a sort button SortButton


Dim Names$(1 To 2000)
Dim NameCount As Integer

Private Sub EnterButton_Click()
  NameCount = NameCount + 1
  Names(NameCount) = Text2.Text
  Text1.Text = Text1.Text & Text2.Text & Chr(13) & Chr(10)
  Text2.Text = ""
End Sub

Private Sub Form_Load()
  NameCount = 0
  Text1.Text = ""
  Text2.Text = ""
End Sub

Private Sub SortButton_Click()
  Dim Done As Integer
  Dim Range As Integer
  Dim Icount As Integer
  Dim Temp As String

  Range = Int(NameCount/2)
  Do While (Range > 0)
    Do
    Done = 1
    For Icount = 1+Range To NameCount Step Range
      If (UCase(Names(Icount - Range)) > UCase(Names(Icount))) Then
        Temp = Names(Icount)
        Names(Icount) = Names(Icount - Range)
        Names(Icount - Range) = Temp
        Done = 0
      End If
    Next Icount
    Loop Until (Done = 1)
  Range = Int(Range/2)
  Loop
  
  Text1.Text = ""
  For Icount = 1 To NameCount
    Text1.Text = Text1.Text & Names(Icount) & Chr(13) & Chr(10)
  Next Icount
  
End Sub

The following is a sort done by merging into an ordered list. The ordered list is managed with a dope vector array. WARNING This version of the code has a bug. If you hit an infinite loop, you may need the Break key to terminate. We will discuss the bug after presenting the preliminary version.


Rem Sample of a Sort by Merging Into a Sorted List
Rem H. J. Bernstein, 7 November 1999
Rem *** WARNING -- This version may loop forever ***

Rem Requires a Form with an output text box Text1
Rem                      an input text box Text2
Rem                        with properties
Rem                          ScrollBars 2 (Vertical)
Rem                          Multiline True
Rem                      an enter button EnterButton
Rem                      a sort button SortButton

Rem **** This is an untested, undebugged version ****


Dim Names$(1 To 2000)
Dim NameOrder(1 To 2000)
Dim NameCount As Integer

Private Sub EnterButton_Click()
  NameCount = NameCount + 1
  Names(NameCount) = Text2.Text
  Text1.Text = Text1.Text & Text2.Text & Chr(13) & Chr(10)
  Text2.Text = ""
End Sub

Private Sub Form_Load()
  NameCount = 0
  Text1.Text = ""
  Text2.Text = ""
End Sub

Private Sub SortButton_Click()
  Dim Range As Integer
  Dim Icount As Integer
  Dim Klo As Integer
  Dim Khi As Integer
  Dim Temp As String
  Dim Ordered as Integer
  Dim Iget as Integer
  
  NameOrder(1) = 1
  Ordered = 1
  
  For Iget = 2 to NameCount
    If (UCase(Names(Iget)) >= UCase(Names(NameOrder(Ordered)))) Then
      Ordered = Ordered+1
      NameOrder(Ordered) = Iget
    ElseIf (UCase(Names(Iget)) <= UCase(Names(NameOrder(1)))) Then
      For Icount = Ordered To 1 Step -1
        NameOrder(Icount+1) = NameOrder(Icount)
      Next Icount
      Ordered = Ordered+1
      NameOrder(1) = Iget
    Else
      Range = Int(Ordered/2)
      Klo = 1
      Khi = Ordered
      Do While (Range > 0)
        If (UCase(Names(Iget)) = UCase(Names(NameOrder(Klo+Range-1)))) Then
          Klo = Klo+Range-1
          Exit Do
        End If
        If (UCase(Names(Iget)) <= UCase(Names(NameOrder(Klo+Range-1)))) Then
          Khi = Klo+Range-1
        Else
          Klo = Klo+Range-1
        End If
        Range = Int((Khi-Klo)/2)
      Loop
      For Icount = Ordered to Klo+1 Step -1
        NameOrder(Icount+1) = NameOrder(Icount)
      Next Icount
      Ordered = Ordered+1
      NameOrder(Klo+1) = Iget
    End If
  Next Iget

  Text1.Text = ""
  For Icount = 1 To NameCount
    REM Originally: ... & Names(Icount) ... which gave the unsorted list
    Text1.Text = Text1.Text & Names(NameOrder(Icount)) & Chr(13) & Chr(10)
  Next Icount
  
End Sub

Now let us turn to the bug. One of the most difficult aspects of algorithms based on binary searches is being certain of the boundary conditions. This code may loop forever if we get to the case Khi = Klo+2. In that case, Range will be set to 1 for the next pass. If that pass sets Klo to Klo+Range-1, we repeat the same values forever. Let us redo the code with comments to help guide what we are doing.


      REM Version of code which will not loop infinitely, and which
      REM sets Klo to a string which can be placed below the
      REM string at Iget

      REM We enter this code knowing that there are at least two
      REM items in the sorted list.  If there are exactly 2, we are
      REM done; we place the new item between them.  If there are
      REM 3 items, we need to examine the middle item, so, in 
      REM contrast to the prior version, we look at Klo+Range
      REM rather than Klo+Range-1

      REM We change the initial calculation of the Range so 1 and 2
      REM give a Range of 0, and we change all references to Range-1
      REM to be references to Range

      Range = Int((Ordered-1)/2)
      Klo = 1
      Khi = Ordered
 
      Do While (Range > 0)

        REM If the item falls on the break, stop here

        If (UCase(Names(Iget)) = UCase(Names(NameOrder(Klo+Range)))) Then
          Klo = Klo+Range
          Exit Do
        End If

        REM Shrink the range to the half containing the item

        If (UCase(Names(Iget)) <= UCase(Names(NameOrder(Klo+Range)))) Then
          Khi = Klo+Range
        Else
          Klo = Klo+Range
        End If
        Range = Int((Khi-Klo)/2)
      Loop

      REM Move everything above Klo up by 1

      For Icount = Ordered to Klo+1 Step -1
        NameOrder(Icount+1) = NameOrder(Icount)
      Next Icount
      Ordered = Ordered+1
      NameOrder(Klo+1) = Iget