Поиск в связных списках
Поиск методом полного перебора — это единственный способ поиска в связных списках. Так как доступ к элементам возможен только при помощи указателей NextCellна следующий элемент, то необходимо проверить по очереди все элементы с начала списка, чтобы найти искомый.
Так же, как и в случае поиска полным перебором в массиве, если список упорядочен, то можно прекратить поиск, если найдется элемент со значением, большим, чем значение искомого элемента.
Public Function LListSearch(target As Long) As SearchCell
Dim cell As SearchCell
NumSearches = 0
Set cell = ListTop.NextCell
Do While Not (cell Is Nothing)
NumSearches = NumSearches + 1
If cell.Value >= target Then Exit Do
Set cell = cell.NextCell
Loop
If Not (cell Is Nothing) Then
If cell.Value = target Then
Set LListSearch = cell ' Элемент найден.
End If
End If
End Function
Программа Searchв архиве с примерами использует этот алгоритм для поиска элементов в связном списке. Этот алгоритм выполняется немного медленнее, чем алгоритм полного перебора в массиве из-за дополнительных накладных расходов, которые связаны с управлением указателями на объекты. Заметьте, что программаSearchстроит связные списки, только если список содержит не более 10.000 элементов.
Чтобы алгоритм выполнялся немного быстрее, в него можно внести еще одно изменение. Если хранить указатель на конец списка, то можно добавить в конец списка ячейку, которая будет содержать искомый элемент. Этот элемент называется сигнальной меткой(sentinel). Это позволяет обрабатывать особый случай конца списка так же, как и все остальные.
В этом случае, добавление метки в конец списка гарантирует, что в конце концов искомый элемент будет найден. При этом программа не может выйти за конец списка, и нет необходимости проверять условие Not (cell Is Nothing)в каждом циклеWhile.
Public Function SentinelSearch(target As Long) As SearchCell
Dim cell As SearchCell
Dim sentinel As New SearchCell
NumSearches = 0
' Установить сигнальную метку.
sentinel.Value = target
Set ListBottom.NextCell = sentinel
' Найти искомый элемент.
Set cell = ListTop.NextCell
Do While cell.Value < target
NumSearches = NumSearches + 1
Set cell = cell.NextCell
Loop
' Определить найден ли искомый элемент.
If Not ((cell Is sentinel) Or _
(cell.Value <> target)) _
Then
Set SentinelSearch = cell ' Элемент найден.
End If
' Удалить сигнальную метку.
Set ListBottom.NextCell = Nothing
End Function
Хотя может показаться, что это изменение незначительно, проверка Not (cell Is Nothing)выполняется в цикле, который вызывается очень часто. Для больших списков этот цикл вызывается множество раз, и выигрыш времени суммируется. ВVisualBasic, этот версия алгоритма поиска в связных списках выполняется на 20 процентов быстрее, чем предыдущая версия. В программеSearchприведены обе версии этого алгоритма, и вы можете сравнить их.
Некоторые алгоритмы используют потоки для ускорения поиска в связных списках. Например, при помощи указателей в ячейках списка можно организовать список в виде двоичного дерева. Поиск элемента с использованием этого дерева займет время порядка O(log(N)), если дерево сбалансировано. Такие структуры данных уже не являются просто списками, поэтому мы не обсуждаем их в этой главе. Чтобы больше узнать о деревьях, обратитесь к 6 и 7 главам этой книги.