Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
(ebook) Visual Studio .NET Mastering Visual Basic.pdf
Скачиваний:
136
Добавлен:
17.08.2013
Размер:
15.38 Mб
Скачать

484 Chapter 11 STORING DATA IN COLLECTIONS

Another form of the Sort method uses a user-supplied function to sort arrays of custom objects. As you recall, arrays can store all types of objects. But the Framework doesn’t know how to sort your custom objects. To sort an array of objects, you must provide your own function that implements the IComparer interface. This form of the Sort method is described in detail in the later section “The IEnumerator and IComparer Interfaces,” where you will also learn how to write functions for sorting your custom objects.

Searching Arrays

Arrays can be searched in two ways: with the BinarySearch method, which works on sorted arrays and is extremely fast; and with the IndexOf (and LastIndexOf) methods, which work regardless of the order of the elements. All three methods search for an instance of an item and return its index. The IndexOf and LastIndexOf methods are similar to the methods by the same name of the String class. They return the index of the first (or last) instance of an object in the array, or the value –1 if the object isn’t found in the array. Both methods are overloaded, and the simplest form of the IndexOf method is:

itemIndex = System.Array.IndexOf(array, object)

where array is the name of the array to be searched and object is the item you’re searching for. The LastIndexOf method’s syntax is identical, but the LastIndexOf method starts searching from the end of the array. If the item you’re searching for is unique in the array, both methods will return the same index.

Another form of the IndexOf and LastIndexOf methods allows you to begin the search at a specific index:

itemIndex = System.Array.IndexOf(array, object, startIndex)

This form of the method starts searching in the segment of the array from startIndex to the end of the array. Finally, you can specify the range of indices where the search will take place with the following form of the method:

itemIndex = System.Array.IndexOf(array, object, startIndex, endIndex)

You can search large arrays more efficiently with the BinarySearch method, if the array is sorted. The simplest form of the BinarySearch method is

System.Array.BinarySearch(array, object)

where array is the name of the array and object the item you’re searching for. To search a section of the array, supply the two indices that delimit the section of the array you wish to sort:

System.Array.BinarySearch(array, startIndex, selLength, object)

If the array contains custom objects, you must provide an IComparer object that compares two elements. This is the same object you supply to the Sort method for custom sorts.

The BinarySearch method returns an integer value, which is the index of the object you’re searching for in the array. If the object argument is not found, the method returns a negative value, which is the negative of the index of the next larger item minus one. This transformation, the negative of a positive number minus one, is called the one’s complement, and other languages provide an operator for it, the tilde (~). The one’s complement of 10 is –11, and the one’s complement of –3 is 2.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

ADVANCED ARRAY TOPICS 485

Why all this complexity? Zero is a valid index, so only a negative value could indicate a failure in the search operation. A value of –1 would indicate that the operation failed, but the BinarySearch method does something better. If it can’t locate the item, it returns the index of the item immediately after the desired item (the first item in the array that exceeds the item you’re searching for). This is a near match, and the BinarySearch method returns a negative value to indicate near matches. Notice that there will always be a near match, unless you’re searching for a value larger than the last value in the array. In this case, the BinarySearch method will return the one’s complement of the array’s upper bound. If your array was declared with 100 elements and the value you’re searching for is an element that’s larger than the last element, the BinarySearch method will return the one’s complement of the value 100 (which is –101).

Tip Like the BinarySearch method, the IndexOf and LastIndexOf methods perform case-sensitive searches. However, because the BinarySearch method reports near matches, it appears as if it performs case-insensitive searches. If the array contains the element “Charles” and you search for “charles,” the IndexOf method will not find the string, while the BinarySearch will find it but will report it as a near match.

The Option Compare statement has no effect on the comparisons performed either by the BinarySearch or by the IndexOf/LastIndexOf methods. If you want to perform case-insensitive comparisons, you must provide your own custom comparer, as described in the section “Custom Sorting,” later in this chapter.

The ArraySearch application, shown in Figure 11.2, demonstrates how to handle exact and near matches reported by the BinarySearch method. The Populate Array button populates an array with 1,000 random strings. The same strings are also displayed on a sorted ListBox control, so that you can view them. The elements have the same order in both the array and the ListBox, so we can use the index reported by the BinarySearch method to locate and select instantly the same item in the ListBox.

Figure 11.2

Searching an array and locating the same element in the ListBox control

The Populate Array button creates 1,000 random strings, each with a length of 3 to 15 characters. Both the length of each string and the characters in it are chosen randomly. You can find the code of the Populate Array button’s Click handler on the CD. This isn’t the most interesting part of the application anyway. When you run the application, message boxes will pop up displaying the

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

486 Chapter 11 STORING DATA IN COLLECTIONS

time it took for each operation: how long it took to populate the array, how long it took to sort it, and how long it took to populate the ListBox. You may wish to experiment with large arrays (100,000 elements or more).

The Search Array button prompts the user for a string with an InputBox and then locates the string with the BinarySearch method in the array. The result is either an exact or a near match, and it’s displayed on a message box. At the same time, the item reported by the BinarySearch method is also selected in the ListBox control.

To test the application, find a string in the list and then click the Search Array button. Enter the entire string (you can use lowercase or uppercase characters; it doesn’t make a difference) and verify that the application reports an exact match and locates the item in the ListBox. Then enter a string that doesn’t exist in the list (or the beginning of an existing string) and see how the BinarySearch handles near matches.

The code behind the Search Array button calls the BinarySearch method and stores the integer returned by the method to the wordIndex variable. Then it examines the value of this variable. If wordIndex is positive, there was an exact match and it’s reported. If wordIndex is negative, the program calculates the one’s complement of this value, which is the index of the near match. The element at this index is reported as a near match. Finally, regardless of the type of the match, the code selects the same item in the ListBox and makes it visible. Listing 11.2 is the code behind the Search Array button.

Listing 11.2: Locating Exact and Near Matches with BinarySearch

Private Sub bttnSearch_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles bttnSearch.Click Dim srchWord As String

Dim wordIndex As Integer

srchWord = InputBox(“Enter word to search for”) wordIndex = System.Array.BinarySearch(words, srchWord) Console.WriteLine(wordIndex)

If wordIndex >= 0 Then

MsgBox(“Words(“ & wordIndex.ToString & “) = “ & _ words(wordIndex), , “EXACT MATCH”)

ListBox1.TopIndex = wordIndex ListBox1.SelectedIndex = wordIndex

Else

MsgBox(“Words(“ & (-wordIndex - 1).ToString & “) = “ & _ words(-wordIndex - 1), , “NEAR MATCH”)

ListBox1.TopIndex = -wordIndex - 1 ListBox1.SelectedIndex = -wordIndex - 1

End If End Sub

Notice that all methods for sorting and searching arrays work with the base data types only. If the array contains custom data types, you must supply your own functions for comparing elements of this type, a process described in detail in the section “The IEnumerator and IComparer Interfaces,” later in this chapter.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

ADVANCED ARRAY TOPICS 487

The Binary Search Algorithm

The BinarySearch method uses a very powerful search algorithm, the binary search algorithm, but it requires that the array be sorted. You need not care about the technical details of the implementation of a method, but in the case of the binary search algorithm, a basic understanding of how it works will help you understand how it performs near matches. To locate an item in a sorted array, this method compares the search string to the array’s middle element. If the search string is smaller, we know that the element is in the first half of the array and we can safely ignore the second half. The same process is repeated with the remaining half of the elements. The search string is compared to the middle element of the reduced array, and after the comparison, we can ignore one half of the reduced array. At each step, the binary search algorithm rejects one half of the items left until it reduces the list to a single item. This is the item we’re searching for. If not, the item is not in the list. To search a list with 1,024 items, the binary search algorithm makes 10 comparisons. At the first step, it rejects 512 elements, then 256, then 128 and so on, until it reaches a single element. For an array of 1,024 × 1,024 (that’s a little more than a million) items, the algorithm makes 20 comparisons to locate the desired item.

If you apply the BinarySearch method on an array that hasn’t been sorted, the method will carry out all the steps and report that the item wasn’t found, even though it may be in the array. The algorithm doesn’t check the order of the elements; it just assumes that they’re sorted. You may also have noticed that, regardless of the outcome, the same number of operations takes place. The binary search algorithm always halves the number of elements in which it attempts to locate the desired element in the array. That’s why you should never apply to the BinarySearch method to an array that hasn’t been sorted yet.

To see what happens when you apply the BinarySearch method to an array that hasn’t been sorted, remove the statement that calls the Sort method in the ArraySearch sample application. The application will keep reporting near matches, even if the string you’re searching is present in the array. The BinarySearch method, assuming that the array is sorted, keeps halving the array by successive comparisons. When it’s left with a single item, which is not the one you’re searching for, it returns the index of the following element and reports a near match. Of course, the near match isn’t close to the element you’re searching for by any stretch of the word—it’s an element that happens to be there when the algorithm finishes. You should never apply the BinarySearch method to an array that hasn’t been sorted.

Sorting an array is an expensive operation, and you can’t afford to continuously sort lengthy arrays. If your array isn’t sorted, you can still search for specific items with the IndexOf and LastIndexOf methods. These methods locate an item in an array and they’re overloaded, similar to the BinarySearch method.

Other Array Operations

The Array class exposes additional methods, which are described briefly in this section.

The Reverse method reverses the order of the elements in an array. The syntax of the Reverse method is

System.Array.Reverse(array)

The Reverse method can’t be applied to an array and reverse its elements. Instead, it returns a new array with the elements of the array passed as argument, only in reverse order. To reverse the order of

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com