52704.fb2 Фундаментальные алгоритмы и структуры данных в Delphi - читать онлайн бесплатно полную версию книги . Страница 50

Фундаментальные алгоритмы и структуры данных в Delphi - читать онлайн бесплатно полную версию книги . Страница 50

Clear;

SLNodeManager.FreeNode(FHead);

inherited Destroy;

end;

А теперь перейдем к методу Enqueue. Он посредством диспетчера узлов распределяет новый узел и устанавливает его указатель данных на вставляемый элемент. Затем используется указатель FTail. Учитывая, что он указывает на последний узел, мы вставляем новый узел за ним, после чего перемещаем указатель на одну позицию вперед - на новый узел, который теперь стал последним.

Листинг 3.28. Метод Enqueue класса TtdQueue

procedure TtdQueue.Enqueue(aItem : pointer);

var

Temp : PslNode;

begin

Temp := PslNode(SLNodeManager.AllocNode);

Temp^.slnData := aItem;

Temp^.slnNext := nil;

{добавить новый узел в конец списка и переместить указатель конечного узла на только что вставленный узел}

FTail^.slnNext := Temp;

FTail := Temp;

inc(FCount);

end;

Метод Dequeue ничуть не сложнее. Сначала он проверяет список на наличие в нем элементов, а затем, пользуясь алгоритмом "удалить после" фиктивного начального узла FHead, удаляет из списка первый узел. Перед освобождением узла с помощью диспетчера узлов метод Dequeue возвращает данные. После выполнения метода количество элементов в списке уменьшается на единицу. Вот здесь и начинается самое интересное. Представьте себе, что из очереди снимается один единственный имеющийся в ней элемент. До выполнения операции Dequeue указатель FTail указывал на последний узел списка, который был одновременно и первым. После снятия элемента с очереди первый узел будет отсутствовать, но указатель FTail все еще указывает на него. Нам нужно сделать так, чтобы после удаления узла в списке FTail указывал на фиктивный начальный элемент. Если же в списке до удаления присутствовало несколько элементов, указатель будет указывать на действительный последний узел.

Листинг 3.29. Метод Dequeue класса TtdQueue

function TtdQueue.Dequeue : pointer;

var

Temp : PslNode;

begin

if (Count = 0) then

qError(tdeQueueIsEmpty, 'Dequeue');

Temp := FHead^.slnNext;

Result := Temp^.slnData;

FHead^.slnNext := Temp^.slnNext;

SLNodeManager.FreeNode(Temp);

dec(FCount);

{если после удаления элемента очередь опустела, переместить указатель последнего элемента на фиктивный начальный узел}

if (Count = 0) then

FTail := FHead;

end;

Остальные методы, Clear, Examine и IsEmpty, еще проще.

Листинг 3.30. Методы Clear, Examine и IsEmpty класса TtdQueue

procedure TtdQueue.Clear;

var

Temp : PslNode;

begin

{удалить все узлы за исключением начального; при возможности освободить все данные}

Temp := FHead^.slnNext;

while (Temp <> nil) do

begin

FHead^.slnNext := Temp^.slnNext;

if Assigned(FDispose) then

FDispose(Temp^.slnData);

SLNodeManager.FreeNode(Temp);

Temp := FHead^.slnNext;