
- •1. Абстрагирование типов
- •1.1. Понятие типа данных
- •1.1.1. Простые типы
- •1.1.2. Абстрактные типы
- •2. Идентификация объектов
- •2.1. Именование
- •2.2. Указание
- •2.2.1. Организация адресного пространства оперативной
- •2.2.2. Понятие указателя
- •2.2.3. Действия над указателями
- •2.2.4. Связывание идентификатора объекта с его
- •3. Время жизни объекта. Классы памяти
- •3.1. Понятие “времени жизни” объекта
- •3.2. Классы памяти
- •3.2.1. Статическая память
- •3.2.2. Автоматическая память
- •3.2.3. Динамическая память
- •4. Динамические структуры данных
- •4.1. Метод вычисляемого и хранимого адреса.
- •4.2. Понятие динамической структуры данных
- •4.3. Линейные динамические структуры данных (списки)
- •4.3.1. Основные виды списков
- •4.4. Односвязные списки
- •4.4.1. Включение узла в начало списка
- •4.4.2. Создание списка из n узлов за счет добавления
- •4.4.3. Создание списка из n узлов за счет добавления
- •4.4.4. Исключение узла из начала списка
- •4.4.5. Перестановка указателя
- •4.4.6. Поиск в списке узла по заданному условию
- •4.4.7. Включение нового узла в список за тем узлом, на
- •4.4.8. Исключение из списка узла за тем узлом, на
- •4.4.9. Исключение из списка узла, на который предварительно
- •4.4.10. Разрушение списка
- •4.4.11. Программный модуль, реализующий операции
- •4.5. Односвязные циклические списки
- •4.6. Двусвязные списки
- •4.6.1. Включение нового узла в список за тем узлом, на
- •4.6.2. Исключение из списка узла, на который
- •4.7. Ортогональные списки (мультисписки)
- •4.8. Разнородные списки
- •4.9. Управление динамической памятью
- •4.9.1. Администратор кучи
- •4.9.2. Алгоритмы выделения участков памяти по запросу
- •4.9.3. Фрагментация
- •4.9.4. Накопление мусора
- •4.9.5. Висящие ссылки
- •5. Множественная интерпретация объектов
- •5.1. Совместимость типов. Приведение и преобразование типов
- •5.2. Методы совмещения типов
- •5.2.1. Запись с вариантной частью
- •5.2.2. Использование директивы absolute
- •5.2.3. Параметры без типа
- •5.2.4. Открытые массивы
- •5.2.5. Наложение масок с помощью указателей
- •6. Рекурсивные структуры данных
- •6.1. Итерация и рекурсия в программировании
- •6.1.1. Понятие рекурсии
- •6.1.2. Итеративная и рекурсивная схема организации
- •6.2. Задача о “ханойских башнях”
- •6.3. Виды рекурсивных структур данных
- •6.3.1. Арифметические выражения
- •6.3.2. Динамические линейные структуры данных: списки
- •6.3.3. Иерархические линейные структуры данных: наборы
- •6.4. Эффективность рекурсивных вычислений
- •7. ИерархическиеНелинейные структуры данных.Деревья
- •7.1. Деревья общего вида
- •7.2. Бинарные деревья
- •7.3. Представление бинарных деревьев
- •7.3.1. Представление бинарных деревьев на статической
- •7.3.2. Представление бинарных деревьев на
- •7.4. Алгоритмы обхода бинарных деревьев
- •7.5. Виды бинарных деревьев
- •7.5.1. Сбалансированные деревья
- •7.5.2. Дихотомические деревья (деревья поиска)
- •7.5.3. Деревья выражений
- •7.6. Программный модуль, реализующий операции
- •Список рекомендуемой литературы
4.5. Односвязные циклические списки
Циклически связанный список(сокращенно – циклический список) обладает той особенностью, что поле связи его последнего элемента не содержит значенияnil, а указывает на первый узел списка. В целях удобства обработки в структуру циклического списка включают специальный узел с особым содержанием информационного поля (на рис. 29 это поле заштриховано), называемыйголовой списка или “сторожем”. Голова списка является дополнительным элементом. Назначение этого элемента состоит в том, чтобы отмечать точку входа в циклический список, а также упростить включение узлов в начало списка и исключение узлов из начала списка. На рис. 29 показана структура односвязного циклического списка с головным элементом.
Рис. 29. Структура односвязного циклического списка с головным узлом
Элемент хранения односвязного циклического списка описывается следующим образом:
Type PList=^List; List= record info: word; link: pList; end; |
{ указатель на узел списка } { описание узла списка } { информационное поле узла } { поле связи узла } |
Var head: PList; |
{ указатель на «голову» списка } |
p: Plist; |
{ вспомогательный указатель } |
Выполнение условия head = nilозначает, что односвязный циклический список не существует. Выполнение условияhead ^. link = head означает, что односвязный циклический список существует, но является пустым, т.е. содержит только головной элемент. Пустой циклический список с головным элементом представляется структурой элементарного кольца (рис. 30).
Рис. 30. Структура элементарного односвязного кольца
Односвязные циклические списки можно использовать для реализации линейных структур, таких как очереди, стеки, списки произвольного вида. При создании очереди новый узел включается в “хвост” списка, т.е. “перед” головным элементом (рис. 31). При создании стека новый узел включается в начало списка, т.е. непосредственно “за” головным элементом (рис. 32).
Рис. 31. Создание очереди на структуре односвязного циклического списка
Рис. 32. Создание стека на структуре односвязного циклического списка
Ниже приведена процедура создания односвязного циклического списка из nузлов.
Procedure Create_Cicl( var head: PList; n: byte ); var p: PList; i: byte; begin new( head ); head^.link:=head; |
{ head – указатель на голову списка } { n – количество узлов в списке }
{ создание элементарного кольца }
| ||
for i:=1 to n do begin |
{ cоздание циклического списка из n узлов } | ||
new( p ); |
{ создание узла списка } | ||
readln(p^.info); |
{ заполнение информационного поля узла } | ||
p^.link:=head^.link; |
{ установка связи между вставленным узлом и cписком} | ||
head^.link:=p; |
{ обновление поля связи головного узла } | ||
end; end; |
|
Т.к. в циклическом списке каждый элемент, в том числе первый и последний, имеют предшественника и последователя (“перед” первым элементом и “за” последним элементом находится голова), все n элементов списка создаются и включаются в список одинаково (см. процедуру Create_Cikl). Каким образом включаются узлы в список при выполнении процедуры Create_Cikl: “за” головным узлом или “перед” ним?Исключение первого или последнего узла циклического списка также не имеет никаких особенностей за счет использования головного элемента. Операции включения / исключения узлов в список произвольного вида, реализованный в виде циклического списка, выполняются так же, как в нецикличесом списке.
В циклическом списке можно получить доступ к любому элементу списка, продвигаясь от произвольного элемента по кольцу. Поиск элемента по заданному условию в односвязном циклическом списке организуется в цикле, включающем операции проверки выполнения условия для текущего элемента, на который ссылается указатель, и перестановки указателя на соседний элемент. В процессе поиска используется вспомогательный указатель, который первоначально следует установить на узел, следующий за головным. Например,
. . . |
| ||
if head <> nil then begin |
{ список существует? } | ||
p:=head^.link; |
{ установить вспомогательный указатель } | ||
while ( p<> head ) and ( p^.info<> значение ) do < тело цикла > |
{ поиск } | ||
end; |
| ||
. . . |
|
Поиск заканчивается либо при обнаружении элемента списка, соответствующего заданному условию (результатом поиска в этом случае является значение указателя, установленного на искомый узел), либо при возвращении к головному узлу после прохождения всего кольца, если элемент, соответствующий условию поиска, не обнаружен (результатом поиска в этом случае является адрес головного узла). Заметим, что в случае пустого списка цикл не выполнится ни разу.
Указатель на головной элемент циклического списка не изменяет своего значения при выполнении любых операций над элементами списка, за исключением разрушения списка. При разрушении следует освободить области памяти, занятые элементами хранения узлов списка и головного элемента, после чего список прекращает свое существование (указательheadследует установить равнымNIL).