- •Оглавление
- •Связные списки, стеки и очереди
- •Односвязные списки
- •Узлы связного списка
- •Создание односвязного списка
- •Вставка и удаление элементов в односвязном списке
- •Прохождение связного списка
- •Создание упорядоченного списка.
- •Использование упорядоченного связного списка для частотного анализа данных
- •Interface
- •Implementation
- •Очереди
- •Задачи.
Прохождение связного списка
Прохождение связного списка также не представляет никаких трудностей. Фактически мы переходим от узла к узлу по указателям Next до достижения указателя nil, который свидетельствует об окончании списка. Вывод на экран содержимого списка, заданного указателем на начало HeadList, будет выглядеть следующим образом
var
HeadList, TempNode : PElem;
begin
…….
TempNode:=HeadList; {Для прохождения по списку нельзя использовать адрес первого элемента HeadList, т.к. потеряем весь список}
WhileTempNode<>nildo { пока список не пустой}
begin
Writeln(TempNode^.Data); {печатаем значение в текущем узле}
TempNode:=TempNode^.Next; {переставляем указатель на следующий элемент}
end;
…….
Очистка связного списка требует небольшого изменения алгоритма, чтобы гарантировать, что мы не ссылаемся на поле Next после освобождения узла (типичная ошибка).
var
HeadList, TempNode : PElem;
begin
…….
WhileHeadList<>nildo { Пока список не пустой}
begin
TempNode:=HeadList{запоминаем адрес первого элемента }
HeadList:=HeadList^.Next; {переставляем указатель начала списка на следующий элемент}
Dispose(TempNode); {удаляем предыдущий элемент }
end;
…….
Обратите внимание, что по окончании цикла Whileуказатель на начало спискаHeadListбудет иметь значениеnil. При работе со связными списками по завершении программы или по окончании работы со списком необходимо провести очистку, и освободить динамическую память, занимаемую такой структурой.
Теперь, когда мы научились проходить по узлам связного списка, давайте вернемся к вопросу, который, наверное, появился у вас пару абзацев назад. А что если нам нужно вставить узел перед заданным узлом? Как это сделать? Единственным решением такой задачи для односвязного списка является прохождение списка и поиск узла, перед которым мы должны вставить новый узел. При прохождении будут использоваться две переменных: одна будет указывать на текущий (This), а вторая на предыдущий узел (Pre). Когда будет найден заданный узел, у нас будет указатель на предыдущий узел, что позволит использовать алгоритм вставки после заданного узла. Вставка нового узла будет происходить между узлами Pre и This. В коде это выглядит следующим образом:
var
HeadList , NewNode, Pre,This : PElem;
Found:Boolean; X, Xnew:integer;
begin
………….
Pre:=nil;
This:=HeadList;
Found:=False; {Место вставки еще не найдено}
While(This<>nil)andnotFounddo{Второе условие – признак окончания поиска при обнаружении позиции вставки, например,This^.data=X. В этом случае вставка нового элемента будет сделана перед элементом со значением, равным Х.}
Begin
Pre:=This;
Found:= This^.data=X;
This:=This^.next;
End;
If Found then
Begin
{Если позиция вставки найдена, то добавляем новый узел между Preи This}
New(NewNode); {выделяем память под новый узел, указатель - NewNode}
NewNode^.Data:=Xnew {заполняем поле Data для нового узла значением Хnew}
Pre^.next:=NewNode; {связываем предыдущий элемент Pre с новым NewNode}
NewNode^.next:=This; {связываем новый элемент NewNode с текущим This }
End;
……
Рис.4 Вставка нового элемента перед заданным узлом.
Работа алгоритма продемонстрирована на Рис.4. Данная вставка не работает, если добавление должно происходить перед первым узлом списка. Для этого необходимо предусмотреть дополнительный код, проверяющий условие This=HeadListилиPre=nil. В этом случае необходимо изменить значение адреса первого узла списка. Например, так
……….
New(NewNode); {выделяем память под новый узел, указатель - NewNode}
NewNode^.Data:=Xnew {заполняем поле Data для нового узла значением Хnew}
NewNode^.next:= HeadList;{связываем новый элемент NewNode с первым HeadList}
HeadList:=NewNode; {связываем первый элемент HeadList с новым NewNode}
……….