
- •Адресные типы
- •Использование динамической памяти
- •Линейные списки
- •Формы представления линейных списков в оперативной памяти
- •Стеки, очереди, деки
- •Представление стека в непрерывной памяти (в виде массива)
- •Представление стека в связанной памяти (в виде односвязного списка)
- •Очереди
- •Представление очереди в непрерывной памяти (в виде массива)
- •Представление очереди в связанной памяти (в виде односвязного списка)
- •Односвязный список
- •Двусвязный список
- •Кольцевые списки
- •Сортировка с помощью прямого выбора
- •Сортировка с помощью прямого обмена (пузырьковая)
- •Оценка затрат на поиск элемента
Представление очереди в связанной памяти (в виде односвязного списка)
рис.7. Очередь в связанной памяти
|
Type QUEUE=^Node; Node=record Info:Real; Next:QUEUE End; Var FRONT, REAR: QUEUE; |
|
Procedure ADDQ (Var FRONT,REAR:Queue; item:Integer); Var newnode:Queue; begin new(newnode); newnode^.info := item; newnode^.next:=nil; if FRONT = Nil then begin FRONT := newnode; REAR:= newnode; end else begin REAR^.next:=newnode; REAR:=newnode; end; end;
|
Function DELETEQ(Var FRONT, REAR:Queue; var error:Integer):Integer; Var Value : Integer; oldhead:Queue; begin value := 0; if FRONT=nil then error := 1 else begin oldhead := FRONT; value:= oldhead^.info; FRONT:= FRONT^.next; if FRONT=nil then REAR:=nil; Freemem(oldhead, sizeof(Queue)); // или Dispose error := 0; End; DELETEQ:=value; end;
|
ДЕКИ
ДЕК (DEQUE, Double-Ended Queue - двусторонняя очередь)
Линейный список, в котором операции включения и исключения элементов (и обычно всякий доступ) разрешены на обоих концах.
Если операция включения (исключения) разрешена только на одном конце списка, то такой дек называют деком с ограниченным входом (выходом).
-
А)
B)
рис.8. Представления дека: А) полный дек в непрерывной памяти; B) дек с ограниченным выходом в связанной памяти.
В статической памяти физическая структура дека идентична структуре кольцевой очереди, а сам дек можно рассматривать как объединение двух очередей, в первой из которых указатель на начало - LEFT, а на конец - RIGHT, а во второй – наоборот (рис. 8А).
Динамическая реализация дека с ограниченным выходом является объединением стека и очереди (рис. 8B).
Односвязный список
Узел односвязного списка содержит одно или несколько информационных полей и поле-ссылку, указывающее на следующий узел списка (рис.9). Для последнего узла поле-ссылка может иметь значение nil или ссылаться на первый узел списка (кольцевой список).
В зависимости от количества полей-ссылок, содержащихся в узлах списка, различают односвязные и двусвязные списки.
рис.9. Узел односвязного списка |
Описание узла: TYPE List=^NODE; Node=record Info:Integer; Next:List; End; |
|
ДОБАВЛЕНИЕ УЗЛА В ОДНОСВЯЗНЫЙ СПИСОК
Выделим случаи добавления узла в начало, конец и середину списка (рис. 10-11, варианты A, B и C соответственно). Введем следующие обозначения:
рис. 10. Односвязный список (добавление узла) |
|
|
|
||
|
||
|
||
|
||
|
|
|
Рис. 11. Добавление узла в начало (А), в конец (B) и середину (C) списка. |
Добавление узла в начало списка (рис. 11А)
New(p);
p^.info:=value;
p^.next:=head;
head:=p;
Создать новый узел p^.
Задать значение информационного поля узла p^.
Установить ссылку из узла p^ на начало списка.
Перенести указатель начала списка (Head) на узел p^.
Добавление узла в конец списка (рис. 11B)
pr:=Head;
while pr^.next<>nil do
pr:=pr^.next;
New(p);
p^.info:=value;
p^.next:=pr^.next; (или p^.next:=nil;)
pr^.next:=p
Переместить ссылку pr на последний узел списка.
Создать новый узел p^.
Задать информационное поле узла p^.
Установить ссылку из узла p^ на nil (или на pr^.next).
Связать последний узел списка с узлом p^.
Добавление между двумя узлами списка (рис. 11C)
pr:=Head; while <условие> do pr:=pr^.next; ... New(p); p^.info:=value; p^.next:=pr^.next; pr^.next:=p |
Новый узел добавляется после узла pr^.
|
Рассмотренные выше варианты добавления узла можно использовать, например, в следующей процедуре.
ПРИМЕР 1. Добавление значения Value в односвязный упорядоченный* список.
*В упорядоченном списке узлы расположены в порядке возрастания (убывания) значений информационных полей.
Procedure AddNode(var Head:list; value:integer);
var pr,p:list;
begin
p:=Head; {Установить ссылку p на начало списка}
pr:=nil; {Узел, предшествующий p^, отсутствует}
while (p<>nil)and(value>p^.info) do {Поиск узла pr^}
begin
pr:=p;
p:=p^.next
end;
new(p);
p^.info:=value;
if pr=nil then {Добавление в начало списка}
begin
p^.next:=Head;
Head:=p;
end
else {Добавление в середину/конец списка}
begin
p^.next:=pr^.next;
pr^.next:=p;
end;
end;
ВОПРОС: Отметьте, что изменится в коде процедуры при включении узла по заданному номеру?
УДАЛЕНИЕ УЗЛА ИЗ ОДНОСВЯЗНОГО СПИСКА
Выделим случаи удаления узла из начала, конца и середины списка (рис. 12), сохранив обозначения, использованные выше при описании добавления узла в список.
|
|
|
|
Рис. 12. Удаление узла из начала (А), конца (B) и середины (C) списка. |
|
ЗАДАНИЕ 2.
Напишите операторы для трех рассмотренных выше вариантов удаления узла из односвязного списка.
Напишите свой вариант процедуры для удаления n-го узла односвязного списка (учесть ситуацию, когда список содержит менее n узлов).
Напишите процедуру вывода содержимого списка и функцию подсчета числа узлов в списке.
ПРИМЕРЫ ДРУГИХ ПОДПРОГРАММ ДЛЯ РАБОТЫ СО СПИСКАМИ
Procedure ForwPrn(p:list); Begin if p<>nil then begin Writeln(p^.info); ForwPrn(p^.next); end; end; |
Procedure BackwPrn(p:list); Begin if p<>nil then begin BackwPrn (p^.next); Writeln(p^.info); end; end; |
function Count(p:list):byte; begin if p=nil then count:=0 else Count:=1+count(p^.next); end; |