(* Copyright (C) Doom 2D: Forever Developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License ONLY.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*)
{$INCLUDE a_modes.inc}
// binary heap
unit binheap;
interface
(*
* CmpObjT: class that contains class methods:
* class function less (const[ref] a, b: KeyT): Boolean;
*)
type
// WARNING! don't put structures into heap, use ponters or ids!
generic TBinaryHeapBase = class(TObject)
private
elem: array of ITP;
elemUsed: Integer;
private
procedure heapify (root: Integer);
public
constructor Create ();
destructor Destroy (); override;
procedure clear ();
procedure insert (val: ITP);
function front (): ITP;
procedure popFront ();
property count: Integer read elemUsed;
end;
type
TBinHeapKeyIntLess = class
public
class function less (const a, b: Integer): Boolean; inline;
end;
TBinHeapKeyIntGreat = class
public
class function less (const a, b: Integer): Boolean; inline;
end;
type
TBinaryHeapIntLess = specialize TBinaryHeapBase;
TBinaryHeapIntGreat = specialize TBinaryHeapBase;
implementation
uses
SysUtils;
// ////////////////////////////////////////////////////////////////////////// //
class function TBinHeapKeyIntLess.less (const a, b: Integer): Boolean; inline; begin result := (a < b); end;
class function TBinHeapKeyIntGreat.less (const a, b: Integer): Boolean; inline; begin result := (a > b); end;
// ////////////////////////////////////////////////////////////////////////// //
constructor TBinaryHeapBase.Create ();
begin
SetLength(elem, 128); // 'cause why not?
elemUsed := 0;
end;
destructor TBinaryHeapBase.Destroy ();
begin
elem := nil;
inherited;
end;
procedure TBinaryHeapBase.clear ();
begin
elemUsed := 0;
end;
procedure TBinaryHeapBase.heapify (root: Integer);
var
smallest, right: Integer;
tmp: ITP;
begin
while true do
begin
smallest := 2*root+1; // left child
if (smallest >= elemUsed) then break; // anyway
right := smallest+1; // right child
if not CmpObjT.less(elem[smallest], elem[root]) then smallest := root;
if (right < elemUsed) and (CmpObjT.less(elem[right], elem[smallest])) then smallest := right;
if (smallest = root) then break;
// swap
tmp := elem[root];
elem[root] := elem[smallest];
elem[smallest] := tmp;
root := smallest;
end;
end;
procedure TBinaryHeapBase.insert (val: ITP);
var
i, par: Integer;
begin
//if (val = nil) then exit;
i := elemUsed;
// grow?
if (i = Length(elem)) then
begin
if (i <= 65536) then par := i*2 else par := i+65536; // arbitrary numbers
SetLength(elem, par);
end;
// increase counter
Inc(elemUsed);
// insert element
while (i <> 0) do
begin
par := (i-1) div 2; // parent
if not CmpObjT.less(val, elem[par]) then break;
elem[i] := elem[par];
i := par;
end;
elem[i] := val;
end;
function TBinaryHeapBase.front (): ITP;
begin
if elemUsed > 0 then result := elem[0] else result := Default(ITP);
end;
procedure TBinaryHeapBase.popFront ();
begin
if (elemUsed > 0) then
begin
Dec(elemUsed);
elem[0] := elem[elemUsed];
heapify(0);
end;
end;
end.