52704.fb2
{добавить дескриптор в конец очереди}
FList.Add(Handle);
Handle^.peInx := pred(FList.Count);
{теперь нужно выполнить его пузырьковый подъемна максимально возможный уровень}
if (FList.Count > 1) then
pqBubbleUp(Handle);
{вернуть дескриптор}
Result := Handle;
end;
Подобно методу Enqueue, все эти косвенные ссылки несколько усложняют метод Dequeue, но в коде все же можно распознать стандартные операции исключения из очереди и просачивания.
Листинг 9.11. Исключение из очереди и просачивание в расширенной очереди по приоритету
procedure TtdPriorityQueueEx.pqTrickleDown(aHandle : TtdPQHandle);
var
FromInx : integer;
MaxInx : integer;
ChildInx : integer;
ChildHandle : PpqexNode;
Handle : PpqexNode absolute aHandle;
begin
{если анализируемый элемент меньше одного из своих дочерних элементов, его нужно поменять местами с большим дочерним элементом и продолжить процесс из новой позиции}
FromInx := Handle^.peInx;
MaxInx := pred(FList.Count);
{вычислить индекс левого дочернего узла}
ChildInx := succ(FromInx * 2);
{если имеется по меньшей мере правый дочерний элемент, необходимо вычислить индекс большего дочернего элемента...}
while (ChildInx <= MaxInx) do
begin
{если есть хоть один правый дочерний узел, вычислить индекс наибольшего дочернего узла}
if ((ChildInx+1) <= MaxInx) and
(FCompare(PpqexNode(FList.List^[ChildInx])^.peItem, PpqexNode(FList.List^[ChildInx+ 1])^.peItem) < 0) then
inc(ChildInx);
{если элемент больше или равен большему дочернему элементу, задача выполнена}
ChildHandle := PpqexNode(FList.List^[ChildInx]);
if (FCompare (Handle^.peItem, ChildHandle^.peItem) >= 0) then
Break;
{в противном случае больший дочерний элемент нужно переместить вверх по дереву, а сам элемент - вниз}
FList.List^[FromInx] ChildHandle;
ChildHandle^.peInx := FromInx;
FromInx := ChildInx;
ChildInx := succ(FromInx * 2);
end;
{сохранить элемент в правильной позиции}
FList.List^[FromInx] := Handle;
Handle^.peInx := FromInx;
end;
function TtdPriorityQueueEx.Dequeue : pointer;
var
Handle : PpqexNode;
begin