
- •Указатели и динамическая память
- •Объявление указателей
- •Выделение и освобождение динамической память
- •Процедуры и функции для работы с динамической памятью
- •Динамические структуры данных Связные списки, стеки и очереди
- •Односвязные (однонаправленные)списки
- •Узлы связного списка
- •Создание односвязного списка
- •Вставка и удаление элементов в односвязном списке
- •Прохождение связного списка
- •Соображения по поводу эффективности
- •Двухсвязные списки
- •Соображения по поводу эффективности
- •Очередь
Двухсвязные списки
После достаточно подробных исследований односвязных списков можно переходить к рассмотрению двухсвязных списков. Как и в случае с односвязными списками, здесь имеется набор связанных между собой узлов, но помимо ссылки на следующий узел существует ссылка и на предыдущий узел:
type
PSimpleNode = ^TSimpleNode;
TSimpleNode = record
Next : PSimpleNode;
Prior : PSimpleNode;
Data : SomeDataType;
end;
Таким образом, двухсвязный список позволяет двигаться по узлам не только вперед, по ссылкам Next, но и назад, по ссылкам Prior. Схематично двухсвязный список показан на рис. 3.4.
Рисунок 3.4. Двухсвязный список
Вставка и удаление элементов в двухсвязном списке
Каким образом вставлять новый узел в двухсвязный список? В односвязном списке для этого нужно было разорвать одну ссылку и вставить две новых, а для двухсвязного списка потребуется разорвать две ссылки и вставить четыре новых. Причем вставку можно выполнять как перед, так и после определенного элемента, поскольку указатель Prior позволяет проходить список в обратном направлении. Фактически операцию "вставить перед" можно запрограммировать как "перейти к предыдущему узлу и вставить после". Поэтому в главе мы рассмотрим только операцию "вставить после".
Ссылка Next нового узла устанавливается на узел, расположенный после заданного узла, а ссылка Next заданного узла устанавливается на новый узел. Для установки обратных ссылок ссылка Prior нового узла устанавливается на заданный узел, а ссылка Prior узла, следующего за новым, устанавливается на новый узел. В коде это выглядит следующим образом:
var
GivenNode, NewNode : PSimpleNode;
begin
• • •
New(NewNode);
.. задать значение поля Data..
NewNode^. Next : = GivenNode^. Next;
GivenNode ^. Next : = NewNode ;
NewNode^.Prior := GivenNode;
NewNode^.Next^.Prior : = NewNode;
В случае с удалением проще всего удалить узел, находящийся после заданного узла. Необходимо установить ссылку Next заданного узла на узел, находящийся после удаляемого, а ссылку Prior узла, находящегося после удаляемого, на заданный узел.
Структурированные типы данных, такие, как массивы, множества, записи, представляют собой статические структуры, так как их размеры неизменны в течение всего времени выполнения программы.
Рисунок 3.5 Вставка нового узла в двухсвязный список
После этих операций удаляемый узел исключен из списка, и его можно удалить. В коде это выглядит следующим образом:
var
GivenNode, NodeToGo : PSimpleNode;
begin
• • •
NodeToGo : = GivenNode^. Next ;
GivenNode^.Next : = NodeToGo^.Next;
NodeToGo^.Next^.Prior : = GivenNode;
Dispose(NodeToGo);
Как и для односвязных списков, здесь для обеих операций существуют специальные случаи: вставка перед первым элементом списка (т.е. новый элемент становиться первым) и удаление первого элемента списка (т.е. первым становится другой элемент). Поскольку в наших рассуждениях первый элемент считается определяющим узлом всего списка, код для этих случаев потребуется написать отдельно
Вставка первого элемента:
var
FirstNode, NewNode : PSimpleNode;
begin
• • •
New(NewNode) ;
.. задать значение поля Data..
NewNode^. Next : = FirstNode;
NewNode^.Prior : = nil ;
FirstNode^.Prior : = NewNode;
FirstNode := NewNode;
Удаление первого элемента:
var
FirstNode, NodeToGo : PSimpleNode;
begin
• • •
NodeToGo:= FirstNode;
FirstNode : = NodeToGo^.Next;
FirstNode^.Prior : = nil;
Dispose(NodeToGo);