- •Оглавление
- •Связные списки, стеки и очереди
- •Односвязные списки
- •Узлы связного списка
- •Создание односвязного списка
- •Вставка и удаление элементов в односвязном списке
- •Прохождение связного списка
- •Создание упорядоченного списка.
- •Использование упорядоченного связного списка для частотного анализа данных
- •Interface
- •Implementation
- •Очереди
- •Задачи.
Узлы связного списка
Перед началом описания операций со связным списком давайте рассмотрим, как каждый узел списка будет представляться в памяти. Знание структуры узла позволит нам более детально рассматривать основные операции со связными списком. Структура узла списка выглядит следующим образом:
type
PElem = ^Elem; {Указатель на элемент списка}
Elem = record {Элемент списка - запись}
Data : TdataType; {Данные, хранящиеся в узле списка (тип - любой) }
Next : PElem; {Указатель на следующий элемент списка}
end;
Тип PElem представляет собой указатель на запись Elem, поле Next которой содержит ссылку на точно такой же узел, а поле Data - сами данные. В приведенном примере тип данных узла задан как TdataType, и должен быть описан пользователем заранее (например, для хранения в списке целых чисел можно записать Type TdataType=Integer). Для перехода по ссылке на следующий элемент нужно написать примерно следующий код:
var
NextNode, CurrentNode : PElem; {где CurrentNode – указатель на текущий элемент,
NextNode – указатель на следующий элемент}
begin
…..
NextNode : = CurrentNode^.Next;
Обращения к данным, находящимся в узле списка с адресом CurrentNode, будет записано так: CurrentNode^.Data:=5; или writeln(CurrentNode^.Data);
Создание односвязного списка
В самом простом случае первый узел в связном списке описывает весь список. Первый узел иногда называют головой списка. В программе очень важно не потерять адрес начала списка, т.к. восстановить после этого список невозможно (узлы списка располагаются в памяти хаотично, образуя логическую цепочку через поле Next). В программе, использующей связные списки, необходимо описать глобальную переменную – указатель на начало списка:
Var HeadList : PElem;
Если HeadList содержит nil, списка еще нет. Таким образом, это начальное значение связного списка. Для определенности, в начале программы указателю на начало списка необходимо присвоить значение nil.
HeadList:=nil {инициализация связного списка}
Вставка и удаление элементов в односвязном списке
Каким образом можно вставить новый элемент в связный список? Или удалить? Оказывается, что для выполнения этих операций требуется выполнить небольшую работу с указателями. Для односвязного списка существует только один вариант вставки - после заданного элемента списка. Нужно установить ссылки так, чтобы указатель Nextнашего нового узла указывал на узел после заданного, а указательNextзаданного узла - на наш новый узел. В коде это выглядит следующим образом:
var
GivenNode, NewNode : PElem; { GivenNode – указатель на заданный узел}
begin
New(NewNode);
Newnode^.Data:=15 ; {задаем значение поля Data}
NewNode ^. Next := GivenNode ^. Next ;
GivenNode ^. Next : = NewNode;
Рис.2 Вставка нового узла в односвязный список.
Аналогично, для удаления простейшим вариантом является удаление элемента, находящегося после заданного узла (GivenNode). В этом случае мы устанавливаем, чтобы указатель Next заданного узла указывал на узел, расположенный после удаляемого. После этого удаляемый узел уже выделен из списка и может быть освобожден. В коде это выглядит следующим образом:
var GivenNode, NodeToGo : PElem begin ……………… NodeToGo := GivenNode^.Next; GivenNode^.Next := NodeToGo^.Next; {b} Dispose(NodeToGo); {c}
Указатель NodeToGo – используется как вспомогательный.
|
Рис.3 Удаление узла из односвязного списка |
Тем не менее, для обеих операции существует специальный случай: вставка перед первым элементом списка (т.е. новый элемент становиться первым) и удаление первого элемента списка (т.е. первым становится другой элемент). Поскольку в наших рассуждениях первый элемент считается определяющим узлом всего списка, код для этих случаев нужно написать отдельно. Вставка перед первым узломHeadListбудет выглядеть следующим образом:
var
HeadList , NewNode : PElem;
begin
………….
New(NewNode); {выделяем память под новый узел, указатель - NewNode}
NewNode^.Data:=X {заполняем поле Data для нового узла значением Х}
NewNode^.Next : = HeadList; {связываем новый узел с первым элементом – головой списка}
HeadList: = NewNode ; {список начинается с нового элемента}
………….
а удаление будет выглядеть так:
var
HeadList, TempNode : PElem;
begin
…….
TempNode:=HeadList; {запоминаем адрес первого элемента}
HeadList:=HeadList^.Next; {начало списка переставляем на следующий элемент}
Dispose(TempNode); {освобождаем память, занимаемую бывшим первым элементом }
……………………
Обратите внимание, что код вставки элемента будет работать даже в случае, когда исходный список пуст, т.е. содержит nil (HeadList = nil, после вставки будет создан первый и единственный элемент списка), а код удаления элемента правильно установит указатель на начало связного списка HeadList в nil, если происходит удаление последнего узла.