{ binary heap priority queue
code contributed by Rassim Eminli }
{$INCLUDE Switches.inc}
unit IPQ;
interface
type
TIntegerArray = array [0 .. $40000000 div sizeof(integer)] of integer;
PIntegerArray = ^TIntegerArray;
TheapItem = record
Item: integer;
Value: integer;
end;
TItemArray = array [0 .. $40000000 div sizeof(TheapItem)] of TheapItem;
PItemArray = ^TItemArray;
TIPQ = class
constructor Create(max: integer);
destructor Destroy; override;
procedure Empty;
function Put(Item, Value: integer): boolean;
function TestPut(Item, Value: integer): boolean;
function Get(var Item, Value: integer): boolean;
private
// n - is the size of the heap.
// fmax - is the max size of the heap.
n, fmax: integer;
// bh - stores (Value, Item) pairs of the heap.
// Ix - stores the positions of pairs in the heap bh.
bh: PItemArray;
Ix: PIntegerArray;
end;
implementation
constructor TIPQ.Create(max: integer);
begin
inherited Create;
fmax := max;
GetMem(bh, fmax * sizeof(TheapItem));
GetMem(Ix, fmax * sizeof(integer));
n := -1;
Empty;
end;
destructor TIPQ.Destroy;
begin
FreeMem(bh);
FreeMem(Ix);
inherited;
end;
procedure TIPQ.Empty;
begin
if n <> 0 then
begin
FillChar(Ix^, fmax * sizeof(integer), 255);
n := 0;
end;
end;
// Parent(i) = (i-1)/2.
function TIPQ.Put(Item, Value: integer): boolean; // O(lg(n))
var
i, j: integer;
lbh: PItemArray;
lIx: PIntegerArray;
begin
lIx := Ix;
lbh := bh;
i := lIx[Item];
if i >= 0 then
begin
if lbh[i].Value <= Value then
begin
result := False;
exit;
end;
end
else
begin
i := n;
Inc(n);
end;
while i > 0 do
begin
j := (i - 1) shr 1; // Parent(i) = (i-1)/2
if Value >= lbh[j].Value then
break;
lbh[i] := lbh[j];
lIx[lbh[i].Item] := i;
i := j;
end;
// Insert the new Item at the insertion point found.
lbh[i].Value := Value;
lbh[i].Item := Item;
lIx[lbh[i].Item] := i;
result := True;
end;
function TIPQ.TestPut(Item, Value: integer): boolean;
var
i: integer;
begin
i := Ix[Item];
result := (i < 0) or (bh[i].Value > Value);
end;
// Left(i) = 2*i+1.
// Right(i) = 2*i+2 => Left(i)+1
function TIPQ.Get(var Item, Value: integer): boolean; // O(lg(n))
var
i, j: integer;
last: TheapItem;
lbh: PItemArray;
begin
if n = 0 then
begin
result := False;
exit;
end;
lbh := bh;
Item := lbh[0].Item;
Value := lbh[0].Value;
Ix[Item] := -1;
dec(n);
if n > 0 then
begin
last := lbh[n];
i := 0;
j := 1;
while j < n do
begin
// Right(i) = Left(i)+1
if (j < n - 1) and (lbh[j].Value > lbh[j + 1].Value) then
Inc(j);
if last.Value <= lbh[j].Value then
break;
lbh[i] := lbh[j];
Ix[lbh[i].Item] := i;
i := j;
j := j shl 1 + 1; // Left(j) = 2*j+1
end;
// Insert the root in the correct place in the heap.
lbh[i] := last;
Ix[last.Item] := i;
end;
result := True;
end;
end.