Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
К2_Допматериалы_15апр.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
2.99 Mб
Скачать

Представление очереди в связанной памяти (в виде односвязного списка)

рис.7. Очередь в связанной памяти

  • FRONT, REAR - указатели на начало и конец очереди соответственно. Если очередь пуста, то FRONT=REAR=nil.

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;

  • В процедуре добавления (ADDQ) не включена проверка переполнения памяти.

  • Удаление объекта из очереди

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;

  • Функция удаления (DELETEQ), помимо значения удаленного узла (value), возвращает код ошибки (error), соответствующий отсутствию элемента в очереди.

ДЕКИ

  • ДЕК (DEQUE, Double-Ended Queue - двусторонняя очередь)

Линейный список, в котором операции включения и исключения элементов (и обычно всякий доступ) разрешены на обоих концах.

  • Если операция включения (исключения) разрешена только на одном конце списка, то такой дек называют деком с ограниченным входом (выходом).

А)

B)

рис.8. Представления дека: А) полный дек в непрерывной памяти; B) дек с ограниченным выходом в связанной памяти.

  • В статической памяти физическая структура дека идентична структуре кольцевой очереди, а сам дек можно рассматривать как объединение двух очередей, в первой из которых указатель на начало - LEFT, а на конец - RIGHT, а во второй – наоборот (рис. 8А).

  • Динамическая реализация дека с ограниченным выходом является объединением стека и очереди (рис. 8B).

Односвязный список

Узел односвязного списка содержит одно или несколько информационных полей и поле-ссылку, указывающее на следующий узел списка (рис.9). Для последнего узла поле-ссылка может иметь значение nil или ссылаться на первый узел списка (кольцевой список).

В зависимости от количества полей-ссылок, содержащихся в узлах списка, различают односвязные и двусвязные списки.

рис.9. Узел односвязного списка

Описание узла:

TYPE

List=^NODE;

Node=record

Info:Integer;

Next:List;

End;

  • тип List - адрес узла списка;

  • тип Node - узел списка;

  • поле Info - хранимое значение элемента списка;

  • поле Next - адрес следующего элемента списка.

  • ДОБАВЛЕНИЕ УЗЛА В ОДНОСВЯЗНЫЙ СПИСОК

Выделим случаи добавления узла в начало, конец и середину списка (рис. 10-11, варианты A, B и C соответственно). Введем следующие обозначения:

рис. 10. Односвязный список (добавление узла)

  • Head - указатель на начало списка.

  • P - ссылка на добавляемый (удаляемый) узел.

  • pr (previous) - ссылка на узел, предшествующий добавляемому/удаляемому.

  • Value значение информационного поля для нового/ удаляемого узла.

  • <условие> - используется для поиска положения добавляемого/ удаляемого узла в списке.

А)

B)

C)

Рис. 11. Добавление узла в начало (А), в конец (B) и середину (C) списка.

  • Добавление узла в начало списка (рис. 11А)

    New(p);

    p^.info:=value;

    p^.next:=head;

    head:=p;

    1. Создать новый узел p^.

    2. Задать значение информационного поля узла p^.

    3. Установить ссылку из узла p^ на начало списка.

    4. Перенести указатель начала списка (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

    1. Переместить ссылку pr на последний узел списка.

    1. Создать новый узел p^.

    2. Задать информационное поле узла p^.

    3. Установить ссылку из узла p^ на nil (или на pr^.next).

    4. Связать последний узел списка с узлом p^.

  • Добавление между двумя узлами списка (рис. 11C)

pr:=Head;

while <условие> do

pr:=pr^.next;

...

New(p);

p^.info:=value;

p^.next:=pr^.next;

pr^.next:=p

Новый узел добавляется после узла pr^.

  1. Переместить ссылку pr на заданный узел списка.

  1. Создать новый узел p^.

  2. Задать информационное поле узла p^.

  3. Установить ссылку из узла p^ на узел pr^.next^.

  4. Связать узел списка pr^ с узлом p^.

Рассмотренные выше варианты добавления узла можно использовать, например, в следующей процедуре.

  • ПРИМЕР 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), сохранив обозначения, использованные выше при описании добавления узла в список.

A)

  • Первый узел (рис. 12А)

  1. Установить ссылку p на начало списка.

  2. Перенести указатель начала списка (Head) на второй узел.

  3. Освободить память, занимаемую узлом p^ (~удалить узел).

B)

  • Последний узел (рис. 12B)

  1. Установить ссылку pr на предпоследний узел, а p - на последний.

  2. Установить ссылку предпоследнего узла на nil (или p^.next).

  3. Освободить память, занимаемую узлом p^.

C)

Рис. 12. Удаление узла из начала (А), конца (B) и середины (C) списка.

  • Между двумя узлами (рис. 12C)

  1. Установить ссылку p на удаляемый узел, а pr на предшествующий ему узел.

  2. Установить ссылку узла pr на узел, следующий за узлом p^.

  3. Освободить память, занимаемую узлом p^.

  • ЗАДАНИЕ 2.

  1. Напишите операторы для трех рассмотренных выше вариантов удаления узла из односвязного списка.

  2. Напишите свой вариант процедуры для удаления n-го узла односвязного списка (учесть ситуацию, когда список содержит менее n узлов).

  3. Напишите процедуру вывода содержимого списка и функцию подсчета числа узлов в списке.

  • ПРИМЕРЫ ДРУГИХ ПОДПРОГРАММ ДЛЯ РАБОТЫ СО СПИСКАМИ

  1. ВЫВОД СПИСКА В ПРЯМОМ ПОРЯДКЕ.

Procedure ForwPrn(p:list);

Begin

if p<>nil then

begin

Writeln(p^.info);

ForwPrn(p^.next);

end;

end;

  1. ВЫВОД СПИСКА В ОБРАТНОМ ПОРЯДКЕ.

Procedure BackwPrn(p:list);

Begin

if p<>nil then

begin

BackwPrn (p^.next);

Writeln(p^.info);

end;

end;

  1. ПОДСЧЕТ ЧИСЛА УЗЛОВ В СПИСКЕ

function Count(p:list):byte;

begin

if p=nil then count:=0

else Count:=1+count(p^.next);

end;