Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Мой курсач готовый.doc
Скачиваний:
4
Добавлен:
06.11.2018
Размер:
272.9 Кб
Скачать

1.2 Перебор связанных списков

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

type

PCell = ^ТСе11;

TCell = record

Value : Longint;

NextCell : PCell;

PrevCell : PCell;

end;

function TSearchForm.LListSearch(target : Longint; top : PCell) : PCell;

begin

top := top^.NextCell;

while (top<>nil) do

begin

if <top^.Value >= target) then break;

top := top^.NextCell;

end;

if (top = nil) then

Result := nil

else if (top^.Value = target) then

Result := top

else

Result := nil;

end;

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

Вы можете внести еще одно изменение в алгоритм перебора связанного списка, чтобы алгоритм выполнялся немного быстрее. Если сохранять указатель на конец списка, то можно добавить в конец списка новую ячейку, которая будет содержать искомое значение. Данный элемент называется меткой и выполняет такую же роль, что и метки, описанные в главе 2. Это позволяет программе обрабатывать частные случаи так же, как и все остальные. В данном случае добавление метки в конец списка гарантирует, что алгоритм в конце концов найдет искомый элемент. Программа не может выйти за пределы конца списка, поэтому нет необходимости каждый раз при выполнений цикла while проверять условие top = nil.

function SentinelSearch(target : Longint; top : PCell) : PCell;

var

bottom_sentinel : TCell;

begin

// Добавление метки.

BottomCell^.NextCell := @bottom_sentinel;

bottom_sentinel.Value := target;

// Обычный поиск

top := top^.NextCell;

while (top^.Value < target) do

top := top^.NextCell;

if ( (top^Value<>target) or (top = @bottom_sentinel)) then

Result := nil

else

Result := top;

// Удаление метки.

BottomCell^.NextCell := nil;

end;

Несмотря на то что такое изменение незначительно, проверка top = nil содержится в часто выполняемом цикле. Для больших списков этот цикл повторяется много раз, поэтому подобная экономия становится значительной. В Delphi такой перебор связанного списка осуществляется приблизительно на 10 % быстрее, чем предыдущая версия. Программа Search демонстрирует обе версии алгоритмов перебора связанных списков, поэтому можно легко сравнить их друг с другом. Некоторые алгоритмы используют потоки для оптимизации перебора. Например, при помощи указателей в ячейках можно организовать список в виде двоичного дерева. Поиск элемента с помощью дерева займет O(logN) шагов, если дерево сбалансировано. Такие структуры данных уже не являются просто списками, поэтому здесь не рассматриваются. Подробную информацию о деревьях можно получить в главах 6 и 7.