1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
{ 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.
|