Иллюстрированный самоучитель по VB.NET

       

Практический пример: специализированная сортировка


Практический пример: специализированная сортировка

Предыдущие примеры выглядят искусственно и относятся к категории «игрушечных программ». В этом разделе мы покажем, как использовать делегаты при специализированной сортировке — одной из стандартных областей применения функций обратного вызова. Общая идея заключается в том, что один метод сортировки в зависимости от ситуации может использовать разные критерии сортировки. Предположим, у вас имеется массив имен: «Mike Item», «Dave Mendlen», «Alan Carter», «Tony Goodhew», «Ari Bixhorn», «Susan Warren»-.

Если вызвать метод Sort класса Array, сортировка будет произведена по именам. А если вы хотите отсортировать массив по фамилиям?

Возможный подход к решению этой задачи описан в главе 5 — вы можете написать собственную реализацию интерфейса IComparer и передать ее Sort. Применение обратного вызова на базе делегатов выглядит чуть более элегантно и теоретически обладает большей гибкостью, поскольку программист может определить собственные процедуры сортировки, которые в конкретной ситуации работают эффективнее стандартных алгоритмов.

Чтобы массив поддерживал сортировку по именам, следует определить класс с несколькими методами Compare и при помощи делегата связать алгоритм сортировки с нужным методом Compare через механизм обратного вызова. В частности, это позволит динамически изменять критерий сортировки во время работы программы.

Прежде всего определяется класс, выполняющий сортировку. Чтобы избежать подробного обсуждения различных алгоритмов сортировки, мы воспользуемся простейшим алгоритмом волновой сортировки:

  • Начать с первого элемента.

  • Последовательно просмотреть все остальные элементы. Если очередной элемент окажется меньше текущего первого элемента, поменять их местами.

  • Начать со второго элемента, просмотреть все остальные элементы.

  • Продолжать до последнего элемента. Основной код волновой сортировки выглядит так:





    For i =bottom To (top - bottom) For j =i + 1 To top

    If Stuff(j) < Stuff(i))Then

    temp = Stuff(i)

    Stuff(i) = Stuff(j)

    Stuff(j) = temp

    End If

    Next j

    Next I

    Чтобы реализовать этот алгоритм с применением функций обратного вызова, необходимо определить класс Special Sort с делегатом, используемым при обратном вызове. Код этого класса приведен ниже:

    1 Public Class Special Sort

    2 ' Определение делегата

    3 Public Delegate Function SpecialCompareCallback(ByVal flrstString _

    As String,ByVal secondString As String) As Boolean

    4 ' Определение процедуры, вызываемой делегатом

    5 Public Shared Sub IfySort(ByVal Stuff As String()._

    ByVal MyCompare As SpecialCompareCallback)

    6 Dim i, j As Integer

    7 Dim temp As String

    8 Dim bottom As Integer = Stuff.GetLowerBound(0)

    9 Dim top As Integer = Stuff.GetUpperBound(0)

    10 For i = bottom To (top = bottom)

    11 For j = i + 1 To top

    12 If MyCompare(Stuff(j). Stuff(i)) Then

    13 temp = Stuff(i)

    14 Stuff(1) - Stuff (j)

    15 Stuff(j) = temp

    16 End If

    17 Next j

    18 Next i

    19 End Sub

    20 End Class

    В строке З определяется делегат, при помощи которого классу передается информация об используемом порядке сортировки. Делегат может инкапсулировать любую функцию, которая, как и все нормальные функции сравнения строк, получает два строковых параметра и возвращает логическую величину.

    В строке 5 определяется общая процедура, одним из параметров которой является переменная с типом делегата. Таким образом, в ключевой строке 12:

    If MyCompare(Stuff(j). Stuff(i)) Then

    функция сравнения, инкапсулированная в делегате MyCompare, может относиться к другому классу! Например, если определить приведенный ниже класс, эта схема позволит использовать любой из его методов Compare (обратите внимание: методы Compare объявлены общими, поэтому для их вызова нам даже не нужно создавать конкретный экземпляр класса):

    Public Class MyCustomCompare

    Public Shared Function TheBasicComparetByVal firstString As String,

    ByVal secondString As String) As Boolean



    Return (firstString <- secondString)

    End Function

    Public Shared Function TheSpecialCompare(ByVal firstString As String.

    ByVal secondString As String)As Boolean Dint tokensl,tokens2 As String()

    tokensl = firstString.Split(Chr(32))

    tokens2 = secondString.Split(Chr(32))

    Return (tokensl(l) <- tokens2(l))

    ' Сравнение по фамилии!

    End Function

    End Class

    Класс содержит две общие функции, которые ниже будут использованы для создания делегатов. Первая функция, TheBasicCompare, просто сравнивает строки в алфавитном порядке. Более интересная функция TheSpecialCompare предполагает, что строка передается в формате «имя фамилия», и сравнивает фамилии, выделяя их при помощи удобной функции Split.

    Остается лишь создать экземпляры класса SpecialSort и делегаты. Это происходит в следующей функции Main (ключевые строки выделены жирным шрифтом):

    1 Module Modulel

    2 Sub Main()

    3 Dim test()As String ={"Mike Iem"."Dave Mendlen"."Alan Carter".

    4 "Tony Goodhew","An Bixhorn"."Susan Warren"}

    5 ' Объявить переменную обратного вызова в форме класс.делегат

    6 Dim MyCallBack As Special Sort.SpecialCompareCal1back

    7 MyCallBack = AddressOf MyCustomCompare.TheBasicCompare

    8 SpecialSort.MySort(test,MyCallBack)

    9 Console.WriteLine("Here is a basic sort by FIRST name")

    10 Dim temp As String

    11 For Each temp In test

    12 Console.WriteLine(temp)

    13 Next

    14 ' Передать другую процедуру сравнения

    15 MyCallBack = AddressOf MyCustomCompare.TheSpecialCompare

    16 Sped al Sort. MySort (test. MyCallBack)

    17 Console.WriteLine()

    18 Console.WriteLineC'Here is a sort by LAST name")

    19 For Each temp In test

    20 Console.WriteLine(temp)

    21 Next

    22 Console. ReadLine()

    23 End Sub

    24 End Module

    В строке 6 объявляется «псевдоуказатель на функцию». Чтобы задать его значение, мы передаем адрес функции с правильной сигнатурой (строки 7-15). Поскольку функции объявлены общими, создавать экземпляр класса MyCustomCompare для этого не нужно.После создания делегата в строках 8 и 16 вызывается нужная процедура сортировки класса Special Sort. Поскольку при вызове MySort передается делегат, процедура обращается к классу MyCustomCompare и узнает, по какому критерию должно осуществляться сравнение.


    Содержание раздела