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