Creating the Item Object and Helper Functions


The example's class object, Item , shown in Listing 34.9, is a simple class that contains only the members for the object and the pointers to the next and previous items in the list.

Listing 34.9 - ITEM.CLS - Item.cls contains the object that will be used in our linked list.


/******************************************************************** 
' Item.cls - This class is simply the data structure for a doubly  
'   linked list. 
'********************************************************************* 
Option Explicit 
'********************************************************************* 
' Data members 
'********************************************************************* 
Public strData As String 
Public intData As Integer 
'********************************************************************* 
' Doubly-Linked List Pointers 
'********************************************************************* 
Public clsItemNext As clsItem 
Public clsItemPrev As clsItem 

By using a class module to create the object, you give yourself the flexibility to create as many data members as you want. However, you must modify your helper functions to support any additions or removal of data members from this class.

Now that you have an Item object, you need to write helper routines that enable you to build and navigate through the linked list. Listing 34.10 includes the InsertAfter() and RemoveItem() functions that are designed to add new elements to the list and remove existing elements. LISTHELPERS.BAS also includes an InsertBefore() function, but Listing 34.10 doesn't show it because it is virtually identical to the InsertAfter() function. Consult the LISTDEMO.VBP project for details on the implementation of the InsertBefore() function.

Listing 34.10 - LISTHELPERS.BAS - Adding and Removing Elements


'********************************************************************* 
' Inserts a new item in the linked list after an existing item 
'********************************************************************* 
Public Function InsertAfter(clsPrevious As clsItem, _ 
  Optional strData$, Optional intData As Integer) As clsItem 
  '***************************************************************** 
  ' If clsPrevious hasn't been initialized, then bail... 
  '***************************************************************** 
  If clsPrevious Is Nothing Then 
      MsgBox "InsertAfter failed: Previous item was invalid", _ 
          vbExclamation 
      Exit Function 
  End If 
  '***************************************************************** 
  ' Create the new item 
  '***************************************************************** 
  Dim clsNewItem As New clsItem 
  '***************************************************************** 
  ' If the clsPrevious is the not the tail item, then the item after 
  ' clsPrevious needs its clsItemPrev pointer set to the new item. 
  '***************************************************************** 
  If Not (clsPrevious.clsItemNext Is Nothing) Then 
      Set clsPrevious.clsItemNext.clsItemPrev = clsNewItem 
  End If 
  '***************************************************************** 
  ' Set the values for the newly created item 
  '***************************************************************** 
  With clsNewItem 
      .strData = strData 
      .intData = intData 
      Set .clsItemPrev = clsPrevious 
      Set .clsItemNext = clsPrevious.clsItemNext 
  End With 
  '***************************************************************** 
  ' Point the previous item to the newly created item 
  '***************************************************************** 
  Set clsPrevious.clsItemNext = clsNewItem 
  '***************************************************************** 
  ' Increment the item count 
  '***************************************************************** 
  mintCount = mintCount + 1 
  '***************************************************************** 
  ' Return a pointer to the newly inserted item 
  '***************************************************************** 
  Set InsertAfter = clsNewItem 
End Function 
'********************************************************************* 
' Remove an item in the doubly linked list 
'********************************************************************* 
Public Function RemoveItem(clsItemToRemove As clsItem) As clsItem 
  '***************************************************************** 
  ' If a valid item was not passed, then bail... 
  '***************************************************************** 
  If clsItemToRemove Is Nothing Then 
      MsgBox "You can't remove an uninitialized item!", vbExclamation 
  End If 
  '***************************************************************** 
  ' If the item to remove is the tail... 
  '***************************************************************** 
  If clsItemToRemove.clsItemNext Is Nothing Then 
      '************************************************************* 
      ' If Next = Nothing & Prev = Nothing, the last item in list! 
      '************************************************************* 
      If clsItemToRemove.clsItemPrev Is Nothing Then 
          MsgBox "Can not remove the last item in the list!", _ 
              vbExclamation 
          '********************************************************* 
          ' Return a pointer to clsItemToRemove 
          '********************************************************* 
          Set RemoveItem = clsItemToRemove 
          Exit Function 
      '************************************************************* 
      ' Otherwise, remove the item and return a pointer to the 
      ' previous item 
      '************************************************************* 
      Else 
          Set clsItemToRemove.clsItemPrev.clsItemNext = _ 
              clsItemToRemove.clsItemNext 
          Set RemoveItem = clsItemToRemove.clsItemPrev 
      End If 
  '***************************************************************** 
  ' Otherwise, something must be after the item to remove... 
  '***************************************************************** 
  Else 
      '************************************************************* 
      ' If clsItemToRemove is the head, them remove the head and 
      ' set a new head of the list. 
      ' OPTIONAL: You may want to raise an error here 
      '************************************************************* 
      If clsItemToRemove.clsItemPrev Is Nothing Then 
          Set clsItemToRemove.clsItemNext.clsItemPrev = _ 
              clsItemToRemove.clsItemPrev 
          Set RemoveItem = clsItemToRemove.clsItemNext 
      '************************************************************* 
      ' Otherwise clsItemToRemove is in the middle of the list... 
      '************************************************************* 
      Else 
          Set clsItemToRemove.clsItemPrev.clsItemNext = clsItemToRemove.clsItemNext 
          Set clsItemToRemove.clsItemNext.clsItemPrev = clsItemToRemove.clsItemPrev 
          Set RemoveItem = clsItemToRemove.clsItemPrev 
      End If 
  End If 
  '***************************************************************** 
  ' Decrement the linked list item count 
  '***************************************************************** 
  mintCount = mintCount - 1 
  '***************************************************************** 
  ' Destroy the item to be removed 
  '***************************************************************** 
  Set clsItemToRemove = Nothing 
End Function 

Although the purposes of these two functions are entirely different, the methodology used to accomplish their result is similar. When you add or remove an item to or from the list, you must manipulate the list's clsItemPrev and clsItemNext member variables. The AddItem() function points these members to the newly created item, whereas the RemoveItem() function points these members to the objects before and after the item being removed. When the operation is complete, both functions return a pointer to a valid object in the list. Closely examine both of these functions to see how various situations influence these functions' code paths.

The GetIndex() function is useful for retrieving a specific element of the collection (see Listing 34.11). You can retrieve the index by using any of the data members of Item as the index or "key." To retrieve the element, the function performs a linear search through the linked list until it finds the requested element. If GetIndex() finds no match, it returns Nothing .

Listing 34.11 - LISTHELPERS.BAS - Retrieving a Specific Element


'********************************************************************* 
' Returns a pointer to a specific item in the list 
'********************************************************************* 
Public Function GetIndex(clsStart As clsItem, Optional strData$, _ 
  Optional intData As Integer) As clsItem 
  '***************************************************************** 
  ' If the user didn't tell us where to start, then bail... 
  '***************************************************************** 
  If clsStart Is Nothing Then Exit Function 
  '***************************************************************** 
  ' If the user didn't tell us which item to select, then bail... 
  '***************************************************************** 
  If intData = 0 And strData = "" Then Exit Function 
  '***************************************************************** 
  ' Dim a pointer for iterating through the linked list 
  '***************************************************************** 
  Dim clsCurItem As clsItem 
  '***************************************************************** 
  ' Set the pointer to the item the user told us to begin with 
  '***************************************************************** 
  Set clsCurItem = clsStart 
  '***************************************************************** 
  ' Linear search through all items in the list 
  '***************************************************************** 
  Do While Not (clsCurItem.clsItemNext Is Nothing) 
      With clsCurItem 
          If .intData = intData Or .strData = strData Then 
              '**************************************************** 
              ' Return a pointer to the found item and exit 
              '**************************************************** 
              Set GetIndex = clsCurItem 
              Exit Function 
          End If 
          Set clsCurItem = .clsItemNext 
      End With 
  Loop 
  '***************************************************************** 
  ' Check the data members of the last item in the list 
  '***************************************************************** 
  With clsCurItem 
      If .intData = intData Or .strData = strData Then 
          '********************************************************* 
          ' Return a pointer to the found item 
          '********************************************************* 
          Set GetIndex = clsCurItem 
      End If 
  End With 
  '***************************************************************** 
  ' If not found, then return Nothing (by not doing anything) 
  '***************************************************************** 
End Function 

The key to the GetIndex() function is the capability to iterate through the linked list. To provide this capability, you create a pointer to the start item and traverse the list. You walk the list by setting the clsCurItem pointer to the clsNextItem member of clsCurItem until you reach the tail