(* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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
type
// WARNING! don't put structures into heap, use ponters or ids!
generic TBinaryHeapBase = class(TObject)
private
type
TBinaryHeapLessFn = function (a, b: ITP): Boolean;
private
elem: array of ITP;
elemUsed: Integer;
lessfn: TBinaryHeapLessFn;
private
procedure heapify (root: Integer);
public
constructor Create (alessfn: TBinaryHeapLessFn);
destructor Destroy (); override;
procedure clear ();
procedure insert (val: ITP);
function front (): ITP;
procedure popFront ();
property count: Integer read elemUsed;
end;
type
TBinaryHeapObj = specialize TBinaryHeapBase;
TBinaryHeapInt = specialize TBinaryHeapBase;
function binHeapNewIntLess (): TBinaryHeapInt;
function binHeapNewIntGreat (): TBinaryHeapInt;
implementation
uses
SysUtils;
// ////////////////////////////////////////////////////////////////////////// //
function intLess (a, b: Integer): Boolean; begin result := (a < b); end;
function intGreat (a, b: Integer): Boolean; begin result := (a > b); end;
function binHeapNewIntLess (): TBinaryHeapInt; begin result := TBinaryHeapInt.Create(@intLess); end;
function binHeapNewIntGreat (): TBinaryHeapInt; begin result := TBinaryHeapInt.Create(@intGreat); end;
// ////////////////////////////////////////////////////////////////////////// //
constructor TBinaryHeapBase.Create (alessfn: TBinaryHeapLessFn);
begin
if not assigned(alessfn) then raise Exception.Create('wutafuck?!');
lessfn := alessfn;
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 lessfn(elem[smallest], elem[root]) then smallest := root;
if (right < elemUsed) and (lessfn(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 lessfn(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.