{ ***************************************************************************** * * * This file is part of the Lazarus Component Library (LCL) * * * * See the file COPYING.LCL, included in this distribution, * * for details about the copyright. * * * * 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. * * * ***************************************************************************** Author: Mattias Gaertner Abstract: TAvgLvlTree is an Average Level binary Tree. This binary tree is always balanced, so that inserting, deleting and finding a node is performed in O(log(#Nodes)). } unit AvgLvlTree; {$mode objfpc}{$H+} interface uses Classes, SysUtils; type TAvgLvlTreeNode = class public Parent, Left, Right: TAvgLvlTreeNode; Balance: integer; Data: Pointer; procedure Clear; function TreeDepth: integer; // longest WAY down. e.g. only one node => 0 ! constructor Create; destructor Destroy; override; end; TAvgLvlTree = class private FOnCompare: TListSortCompare; FCount: integer; procedure BalanceAfterInsert(ANode: TAvgLvlTreeNode); procedure BalanceAfterDelete(ANode: TAvgLvlTreeNode); function FindInsertPos(Data: Pointer): TAvgLvlTreeNode; procedure SetOnCompare(const AValue: TListSortCompare); public Root: TAvgLvlTreeNode; function Find(Data: Pointer): TAvgLvlTreeNode; function FindKey(Key: Pointer; OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode; function FindSuccessor(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode; function FindPrecessor(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode; function FindLowest: TAvgLvlTreeNode; function FindHighest: TAvgLvlTreeNode; function FindNearest(Data: Pointer): TAvgLvlTreeNode; function FindPointer(Data: Pointer): TAvgLvlTreeNode; function FindLeftMost(Data: Pointer): TAvgLvlTreeNode; function FindRightMost(Data: Pointer): TAvgLvlTreeNode; function FindLeftMostKey(Key: Pointer; OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode; function FindRightMostKey(Key: Pointer; OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode; function FindLeftMostSameKey(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode; function FindRightMostSameKey(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode; procedure Add(ANode: TAvgLvlTreeNode); function Add(Data: Pointer): TAvgLvlTreeNode; procedure Delete(ANode: TAvgLvlTreeNode); procedure Remove(Data: Pointer); procedure RemovePointer(Data: Pointer); procedure MoveDataLeftMost(var ANode: TAvgLvlTreeNode); procedure MoveDataRightMost(var ANode: TAvgLvlTreeNode); property OnCompare: TListSortCompare read FOnCompare write SetOnCompare; procedure Clear; procedure FreeAndClear; procedure FreeAndDelete(ANode: TAvgLvlTreeNode); property Count: integer read FCount; function ConsistencyCheck: integer; procedure WriteReportToStream(s: TStream; var StreamSize: integer); function ReportAsString: string; constructor Create(OnCompareMethod: TListSortCompare); constructor Create; destructor Destroy; override; end; TAvgLvlTreeNodeMemManager = class private FFirstFree: TAvgLvlTreeNode; FFreeCount: integer; FCount: integer; FMinFree: integer; FMaxFreeRatio: integer; procedure SetMaxFreeRatio(NewValue: integer); procedure SetMinFree(NewValue: integer); procedure DisposeFirstFreeNode; public procedure DisposeNode(ANode: TAvgLvlTreeNode); function NewNode: TAvgLvlTreeNode; property MinimumFreeNode: integer read FMinFree write SetMinFree; property MaximumFreeNodeRatio: integer read FMaxFreeRatio write SetMaxFreeRatio; // in one eighth steps property Count: integer read FCount; procedure Clear; constructor Create; destructor Destroy; override; end; implementation var NodeMemManager: TAvgLvlTreeNodeMemManager; function ComparePointer(Data1, Data2: Pointer): integer; begin if Data1>Data2 then Result:=-1 else if Data1nil then begin InsertPos:=FindInsertPos(ANode.Data); InsertComp:=fOnCompare(ANode.Data,InsertPos.Data); ANode.Parent:=InsertPos; if InsertComp<0 then begin // insert to the left InsertPos.Left:=ANode; end else begin // insert to the right InsertPos.Right:=ANode; end; BalanceAfterInsert(ANode); end else begin Root:=ANode; ANode.Parent:=nil; end; end; function TAvgLvlTree.FindLowest: TAvgLvlTreeNode; begin Result:=Root; if Result<>nil then while Result.Left<>nil do Result:=Result.Left; end; function TAvgLvlTree.FindHighest: TAvgLvlTreeNode; begin Result:=Root; if Result<>nil then while Result.Right<>nil do Result:=Result.Right; end; procedure TAvgLvlTree.BalanceAfterDelete(ANode: TAvgLvlTreeNode); var OldParent, OldRight, OldRightLeft, OldLeft, OldLeftRight, OldRightLeftLeft, OldRightLeftRight, OldLeftRightLeft, OldLeftRightRight : TAvgLvlTreeNode; begin if (ANode=nil) then exit; if ((ANode.Balance=+1) or (ANode.Balance=-1)) then exit; OldParent:=ANode.Parent; if (ANode.Balance=0) then begin // Treeheight has decreased by one if (OldParent<>nil) then begin if(OldParent.Left=ANode) then Inc(OldParent.Balance) else Dec(OldParent.Balance); BalanceAfterDelete(OldParent); end; exit; end; if (ANode.Balance=+2) then begin // Node is overweighted to the right OldRight:=ANode.Right; if (OldRight.Balance>=0) then begin // OldRight.Balance=={0 or -1} // rotate left OldRightLeft:=OldRight.Left; if (OldParent<>nil) then begin if (OldParent.Left=ANode) then OldParent.Left:=OldRight else OldParent.Right:=OldRight; end else Root:=OldRight; ANode.Parent:=OldRight; ANode.Right:=OldRightLeft; OldRight.Parent:=OldParent; OldRight.Left:=ANode; if (OldRightLeft<>nil) then OldRightLeft.Parent:=ANode; ANode.Balance:=(1-OldRight.Balance); Dec(OldRight.Balance); BalanceAfterDelete(OldRight); end else begin // OldRight.Balance=-1 // double rotate right left OldRightLeft:=OldRight.Left; OldRightLeftLeft:=OldRightLeft.Left; OldRightLeftRight:=OldRightLeft.Right; if (OldParent<>nil) then begin if (OldParent.Left=ANode) then OldParent.Left:=OldRightLeft else OldParent.Right:=OldRightLeft; end else Root:=OldRightLeft; ANode.Parent:=OldRightLeft; ANode.Right:=OldRightLeftLeft; OldRight.Parent:=OldRightLeft; OldRight.Left:=OldRightLeftRight; OldRightLeft.Parent:=OldParent; OldRightLeft.Left:=ANode; OldRightLeft.Right:=OldRight; if (OldRightLeftLeft<>nil) then OldRightLeftLeft.Parent:=ANode; if (OldRightLeftRight<>nil) then OldRightLeftRight.Parent:=OldRight; if (OldRightLeft.Balance<=0) then ANode.Balance:=0 else ANode.Balance:=-1; if (OldRightLeft.Balance>=0) then OldRight.Balance:=0 else OldRight.Balance:=+1; OldRightLeft.Balance:=0; BalanceAfterDelete(OldRightLeft); end; end else begin // Node.Balance=-2 // Node is overweighted to the left OldLeft:=ANode.Left; if (OldLeft.Balance<=0) then begin // rotate right OldLeftRight:=OldLeft.Right; if (OldParent<>nil) then begin if (OldParent.Left=ANode) then OldParent.Left:=OldLeft else OldParent.Right:=OldLeft; end else Root:=OldLeft; ANode.Parent:=OldLeft; ANode.Left:=OldLeftRight; OldLeft.Parent:=OldParent; OldLeft.Right:=ANode; if (OldLeftRight<>nil) then OldLeftRight.Parent:=ANode; ANode.Balance:=(-1-OldLeft.Balance); Inc(OldLeft.Balance); BalanceAfterDelete(OldLeft); end else begin // OldLeft.Balance = 1 // double rotate left right OldLeftRight:=OldLeft.Right; OldLeftRightLeft:=OldLeftRight.Left; OldLeftRightRight:=OldLeftRight.Right; if (OldParent<>nil) then begin if (OldParent.Left=ANode) then OldParent.Left:=OldLeftRight else OldParent.Right:=OldLeftRight; end else Root:=OldLeftRight; ANode.Parent:=OldLeftRight; ANode.Left:=OldLeftRightRight; OldLeft.Parent:=OldLeftRight; OldLeft.Right:=OldLeftRightLeft; OldLeftRight.Parent:=OldParent; OldLeftRight.Left:=OldLeft; OldLeftRight.Right:=ANode; if (OldLeftRightLeft<>nil) then OldLeftRightLeft.Parent:=OldLeft; if (OldLeftRightRight<>nil) then OldLeftRightRight.Parent:=ANode; if (OldLeftRight.Balance>=0) then ANode.Balance:=0 else ANode.Balance:=+1; if (OldLeftRight.Balance<=0) then OldLeft.Balance:=0 else OldLeft.Balance:=-1; OldLeftRight.Balance:=0; BalanceAfterDelete(OldLeftRight); end; end; end; procedure TAvgLvlTree.BalanceAfterInsert(ANode: TAvgLvlTreeNode); var OldParent, OldParentParent, OldRight, OldRightLeft, OldRightRight, OldLeft, OldLeftLeft, OldLeftRight: TAvgLvlTreeNode; begin OldParent:=ANode.Parent; if (OldParent=nil) then exit; if (OldParent.Left=ANode) then begin // Node is left son dec(OldParent.Balance); if (OldParent.Balance=0) then exit; if (OldParent.Balance=-1) then begin BalanceAfterInsert(OldParent); exit; end; // OldParent.Balance=-2 if (ANode.Balance=-1) then begin // rotate OldRight:=ANode.Right; OldParentParent:=OldParent.Parent; if (OldParentParent<>nil) then begin // OldParent has GrandParent. GrandParent gets new child if (OldParentParent.Left=OldParent) then OldParentParent.Left:=ANode else OldParentParent.Right:=ANode; end else begin // OldParent was root node. New root node Root:=ANode; end; ANode.Parent:=OldParentParent; ANode.Right:=OldParent; OldParent.Parent:=ANode; OldParent.Left:=OldRight; if (OldRight<>nil) then OldRight.Parent:=OldParent; ANode.Balance:=0; OldParent.Balance:=0; end else begin // Node.Balance = +1 // double rotate OldParentParent:=OldParent.Parent; OldRight:=ANode.Right; OldRightLeft:=OldRight.Left; OldRightRight:=OldRight.Right; if (OldParentParent<>nil) then begin // OldParent has GrandParent. GrandParent gets new child if (OldParentParent.Left=OldParent) then OldParentParent.Left:=OldRight else OldParentParent.Right:=OldRight; end else begin // OldParent was root node. new root node Root:=OldRight; end; OldRight.Parent:=OldParentParent; OldRight.Left:=ANode; OldRight.Right:=OldParent; ANode.Parent:=OldRight; ANode.Right:=OldRightLeft; OldParent.Parent:=OldRight; OldParent.Left:=OldRightRight; if (OldRightLeft<>nil) then OldRightLeft.Parent:=ANode; if (OldRightRight<>nil) then OldRightRight.Parent:=OldParent; if (OldRight.Balance<=0) then ANode.Balance:=0 else ANode.Balance:=-1; if (OldRight.Balance=-1) then OldParent.Balance:=1 else OldParent.Balance:=0; OldRight.Balance:=0; end; end else begin // Node is right son Inc(OldParent.Balance); if (OldParent.Balance=0) then exit; if (OldParent.Balance=+1) then begin BalanceAfterInsert(OldParent); exit; end; // OldParent.Balance = +2 if(ANode.Balance=+1) then begin // rotate OldLeft:=ANode.Left; OldParentParent:=OldParent.Parent; if (OldParentParent<>nil) then begin // Parent has GrandParent . GrandParent gets new child if(OldParentParent.Left=OldParent) then OldParentParent.Left:=ANode else OldParentParent.Right:=ANode; end else begin // OldParent was root node . new root node Root:=ANode; end; ANode.Parent:=OldParentParent; ANode.Left:=OldParent; OldParent.Parent:=ANode; OldParent.Right:=OldLeft; if (OldLeft<>nil) then OldLeft.Parent:=OldParent; ANode.Balance:=0; OldParent.Balance:=0; end else begin // Node.Balance = -1 // double rotate OldLeft:=ANode.Left; OldParentParent:=OldParent.Parent; OldLeftLeft:=OldLeft.Left; OldLeftRight:=OldLeft.Right; if (OldParentParent<>nil) then begin // OldParent has GrandParent . GrandParent gets new child if (OldParentParent.Left=OldParent) then OldParentParent.Left:=OldLeft else OldParentParent.Right:=OldLeft; end else begin // OldParent was root node . new root node Root:=OldLeft; end; OldLeft.Parent:=OldParentParent; OldLeft.Left:=OldParent; OldLeft.Right:=ANode; ANode.Parent:=OldLeft; ANode.Left:=OldLeftRight; OldParent.Parent:=OldLeft; OldParent.Right:=OldLeftLeft; if (OldLeftLeft<>nil) then OldLeftLeft.Parent:=OldParent; if (OldLeftRight<>nil) then OldLeftRight.Parent:=ANode; if (OldLeft.Balance>=0) then ANode.Balance:=0 else ANode.Balance:=+1; if (OldLeft.Balance=+1) then OldParent.Balance:=-1 else OldParent.Balance:=0; OldLeft.Balance:=0; end; end; end; procedure TAvgLvlTree.Clear; procedure DeleteNode(ANode: TAvgLvlTreeNode); begin if ANode<>nil then begin if ANode.Left<>nil then DeleteNode(ANode.Left); if ANode.Right<>nil then DeleteNode(ANode.Right); end; NodeMemManager.DisposeNode(ANode); end; // Clear begin DeleteNode(Root); Root:=nil; FCount:=0; end; constructor TAvgLvlTree.Create(OnCompareMethod: TListSortCompare); begin inherited Create; FOnCompare:=OnCompareMethod; FCount:=0; end; constructor TAvgLvlTree.Create; begin Create(@ComparePointer); end; procedure TAvgLvlTree.Delete(ANode: TAvgLvlTreeNode); var OldParent, OldLeft, OldRight, Successor, OldSuccParent, OldSuccLeft, OldSuccRight: TAvgLvlTreeNode; OldBalance: integer; begin OldParent:=ANode.Parent; OldBalance:=ANode.Balance; ANode.Parent:=nil; ANode.Balance:=0; if ((ANode.Left=nil) and (ANode.Right=nil)) then begin // Node is Leaf (no children) if (OldParent<>nil) then begin // Node has parent if (OldParent.Left=ANode) then begin // Node is left Son of OldParent OldParent.Left:=nil; Inc(OldParent.Balance); end else begin // Node is right Son of OldParent OldParent.Right:=nil; Dec(OldParent.Balance); end; BalanceAfterDelete(OldParent); end else begin // Node is the only node of tree Root:=nil; end; dec(FCount); NodeMemManager.DisposeNode(ANode); exit; end; if (ANode.Right=nil) then begin // Left is only son // and because DelNode is AVL, Right has no childrens // replace DelNode with Left OldLeft:=ANode.Left; ANode.Left:=nil; OldLeft.Parent:=OldParent; if (OldParent<>nil) then begin if (OldParent.Left=ANode) then begin OldParent.Left:=OldLeft; Inc(OldParent.Balance); end else begin OldParent.Right:=OldLeft; Dec(OldParent.Balance); end; BalanceAfterDelete(OldParent); end else begin Root:=OldLeft; end; dec(FCount); NodeMemManager.DisposeNode(ANode); exit; end; if (ANode.Left=nil) then begin // Right is only son // and because DelNode is AVL, Left has no childrens // replace DelNode with Right OldRight:=ANode.Right; ANode.Right:=nil; OldRight.Parent:=OldParent; if (OldParent<>nil) then begin if (OldParent.Left=ANode) then begin OldParent.Left:=OldRight; Inc(OldParent.Balance); end else begin OldParent.Right:=OldRight; Dec(OldParent.Balance); end; BalanceAfterDelete(OldParent); end else begin Root:=OldRight; end; dec(FCount); NodeMemManager.DisposeNode(ANode); exit; end; // DelNode has both: Left and Right // Replace ANode with symmetric Successor Successor:=FindSuccessor(ANode); OldLeft:=ANode.Left; OldRight:=ANode.Right; OldSuccParent:=Successor.Parent; OldSuccLeft:=Successor.Left; OldSuccRight:=Successor.Right; ANode.Balance:=Successor.Balance; Successor.Balance:=OldBalance; if (OldSuccParent<>ANode) then begin // at least one node between ANode and Successor ANode.Parent:=Successor.Parent; if (OldSuccParent.Left=Successor) then OldSuccParent.Left:=ANode else OldSuccParent.Right:=ANode; Successor.Right:=OldRight; OldRight.Parent:=Successor; end else begin // Successor is right son of ANode ANode.Parent:=Successor; Successor.Right:=ANode; end; Successor.Left:=OldLeft; if OldLeft<>nil then OldLeft.Parent:=Successor; Successor.Parent:=OldParent; ANode.Left:=OldSuccLeft; if ANode.Left<>nil then ANode.Left.Parent:=ANode; ANode.Right:=OldSuccRight; if ANode.Right<>nil then ANode.Right.Parent:=ANode; if (OldParent<>nil) then begin if (OldParent.Left=ANode) then OldParent.Left:=Successor else OldParent.Right:=Successor; end else Root:=Successor; // delete Node as usual Delete(ANode); end; procedure TAvgLvlTree.Remove(Data: Pointer); var ANode: TAvgLvlTreeNode; begin ANode:=Find(Data); if ANode<>nil then Delete(ANode); end; procedure TAvgLvlTree.RemovePointer(Data: Pointer); var ANode: TAvgLvlTreeNode; begin ANode:=FindPointer(Data); if ANode<>nil then Delete(ANode); end; destructor TAvgLvlTree.Destroy; begin Clear; inherited Destroy; end; function TAvgLvlTree.Find(Data: Pointer): TAvgLvlTreeNode; var Comp: integer; begin Result:=Root; while (Result<>nil) do begin Comp:=fOnCompare(Data,Result.Data); if Comp=0 then exit; if Comp<0 then begin Result:=Result.Left end else begin Result:=Result.Right end; end; end; function TAvgLvlTree.FindKey(Key: Pointer; OnCompareKeyWithData: TListSortCompare ): TAvgLvlTreeNode; var Comp: integer; begin Result:=Root; while (Result<>nil) do begin Comp:=OnCompareKeyWithData(Key,Result.Data); if Comp=0 then exit; if Comp<0 then begin Result:=Result.Left end else begin Result:=Result.Right end; end; end; function TAvgLvlTree.FindLeftMostKey(Key: Pointer; OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode; begin Result:=FindLeftMostSameKey(FindKey(Key,OnCompareKeyWithData)); end; function TAvgLvlTree.FindRightMostKey(Key: Pointer; OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode; begin Result:=FindRightMostSameKey(FindKey(Key,OnCompareKeyWithData)); end; function TAvgLvlTree.FindLeftMostSameKey(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode; var LeftNode: TAvgLvlTreeNode; Data: Pointer; begin if ANode<>nil then begin Data:=ANode.Data; Result:=ANode; repeat LeftNode:=FindPrecessor(Result); if (LeftNode=nil) or (fOnCompare(Data,LeftNode.Data)<>0) then break; Result:=LeftNode; until false; end else begin Result:=nil; end; end; function TAvgLvlTree.FindRightMostSameKey(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode; var RightNode: TAvgLvlTreeNode; Data: Pointer; begin if ANode<>nil then begin Data:=ANode.Data; Result:=ANode; repeat RightNode:=FindSuccessor(Result); if (RightNode=nil) or (fOnCompare(Data,RightNode.Data)<>0) then break; Result:=RightNode; until false; end else begin Result:=nil; end; end; function TAvgLvlTree.FindNearest(Data: Pointer): TAvgLvlTreeNode; var Comp: integer; begin Result:=Root; while (Result<>nil) do begin Comp:=fOnCompare(Data,Result.Data); if Comp=0 then exit; if Comp<0 then begin if Result.Left<>nil then Result:=Result.Left else exit; end else begin if Result.Right<>nil then Result:=Result.Right else exit; end; end; end; function TAvgLvlTree.FindPointer(Data: Pointer): TAvgLvlTreeNode; begin Result:=FindLeftMost(Data); while (Result<>nil) do begin if Result.Data=Data then break; Result:=FindSuccessor(Result); if fOnCompare(Data,Result.Data)<>0 then Result:=nil; end; end; function TAvgLvlTree.FindLeftMost(Data: Pointer): TAvgLvlTreeNode; var Left: TAvgLvlTreeNode; begin Result:=Find(Data); while (Result<>nil) do begin Left:=FindPrecessor(Result); if (Left=nil) or (fOnCompare(Data,Left.Data)<>0) then break; Result:=Left; end; end; function TAvgLvlTree.FindRightMost(Data: Pointer): TAvgLvlTreeNode; var Right: TAvgLvlTreeNode; begin Result:=Find(Data); while (Result<>nil) do begin Right:=FindSuccessor(Result); if (Right=nil) or (fOnCompare(Data,Right.Data)<>0) then break; Result:=Right; end; end; function TAvgLvlTree.FindInsertPos(Data: Pointer): TAvgLvlTreeNode; var Comp: integer; begin Result:=Root; while (Result<>nil) do begin Comp:=fOnCompare(Data,Result.Data); if Comp<0 then begin if Result.Left<>nil then Result:=Result.Left else exit; end else begin if Result.Right<>nil then Result:=Result.Right else exit; end; end; end; function TAvgLvlTree.FindSuccessor(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode; begin Result:=ANode.Right; if Result<>nil then begin while (Result.Left<>nil) do Result:=Result.Left; end else begin Result:=ANode; while (Result.Parent<>nil) and (Result.Parent.Right=Result) do Result:=Result.Parent; Result:=Result.Parent; end; end; function TAvgLvlTree.FindPrecessor(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode; begin Result:=ANode.Left; if Result<>nil then begin while (Result.Right<>nil) do Result:=Result.Right; end else begin Result:=ANode; while (Result.Parent<>nil) and (Result.Parent.Left=Result) do Result:=Result.Parent; Result:=Result.Parent; end; end; procedure TAvgLvlTree.MoveDataLeftMost(var ANode: TAvgLvlTreeNode); var LeftMost, PreNode: TAvgLvlTreeNode; Data: Pointer; begin if ANode=nil then exit; LeftMost:=ANode; repeat PreNode:=FindPrecessor(LeftMost); if (PreNode=nil) or (FOnCompare(ANode,PreNode)<>0) then break; LeftMost:=PreNode; until false; if LeftMost=ANode then exit; Data:=LeftMost.Data; LeftMost.Data:=ANode.Data; ANode.Data:=Data; ANode:=LeftMost; end; procedure TAvgLvlTree.MoveDataRightMost(var ANode: TAvgLvlTreeNode); var RightMost, PostNode: TAvgLvlTreeNode; Data: Pointer; begin if ANode=nil then exit; RightMost:=ANode; repeat PostNode:=FindSuccessor(RightMost); if (PostNode=nil) or (FOnCompare(ANode,PostNode)<>0) then break; RightMost:=PostNode; until false; if RightMost=ANode then exit; Data:=RightMost.Data; RightMost.Data:=ANode.Data; ANode.Data:=Data; ANode:=RightMost; end; function TAvgLvlTree.ConsistencyCheck: integer; var RealCount: integer; function CheckNode(ANode: TAvgLvlTreeNode): integer; var LeftDepth, RightDepth: integer; begin if ANode=nil then begin Result:=0; exit; end; inc(RealCount); // test left son if ANode.Left<>nil then begin if ANode.Left.Parent<>ANode then begin Result:=-2; exit; end; if fOnCompare(ANode.Left.Data,ANode.Data)>0 then begin writeln('CCC-3 ',HexStr(Cardinal(ANode.Data),8),' ',HexStr(Cardinal(ANode.Left.Data),8)); Result:=-3; exit; end; Result:=CheckNode(ANode.Left); if Result<>0 then exit; end; // test right son if ANode.Right<>nil then begin if ANode.Right.Parent<>ANode then begin Result:=-4; exit; end; if fOnCompare(ANode.Data,ANode.Right.Data)>0 then begin writeln('CCC-5 ',HexStr(Cardinal(ANode.Data),8),' ',HexStr(Cardinal(ANode.Right.Data),8)); Result:=-5; exit; end; Result:=CheckNode(ANode.Right); if Result<>0 then exit; end; // test balance if ANode.Left<>nil then LeftDepth:=ANode.Left.TreeDepth+1 else LeftDepth:=0; if ANode.Right<>nil then RightDepth:=ANode.Right.TreeDepth+1 else RightDepth:=0; if ANode.Balance<>(RightDepth-LeftDepth) then begin Result:=-6; exit; end; // ok Result:=0; end; // TAvgLvlTree.ConsistencyCheck begin RealCount:=0; Result:=CheckNode(Root); if Result<>0 then exit; if FCount<>RealCount then begin Result:=-1; exit; end; end; procedure TAvgLvlTree.FreeAndClear; procedure FreeNode(ANode: TAvgLvlTreeNode); begin if ANode=nil then exit; FreeNode(ANode.Left); FreeNode(ANode.Right); if ANode.Data<>nil then TObject(ANode.Data).Free; ANode.Data:=nil; end; // TAvgLvlTree.FreeAndClear begin // free all data FreeNode(Root); // free all nodes Clear; end; procedure TAvgLvlTree.FreeAndDelete(ANode: TAvgLvlTreeNode); var OldData: TObject; begin OldData:=TObject(ANode.Data); Delete(ANode); OldData.Free; end; procedure TAvgLvlTree.WriteReportToStream(s: TStream; var StreamSize: integer); var h: string; procedure WriteStr(const Txt: string); begin if s<>nil then s.Write(Txt[1],length(Txt)); inc(StreamSize,length(Txt)); end; procedure WriteTreeNode(ANode: TAvgLvlTreeNode; const Prefix: string); var b: string; begin if ANode=nil then exit; WriteTreeNode(ANode.Right,Prefix+' '); b:=Prefix+HexStr(Cardinal(ANode.Data),8)+' ' +' Self='+HexStr(Cardinal(ANode),8) +' Parent='+HexStr(Cardinal(ANode.Parent),8) +' Balance='+IntToStr(ANode.Balance) +#13#10; WriteStr(b); WriteTreeNode(ANode.Left,Prefix+' '); end; // TAvgLvlTree.WriteReportToStream begin h:='Consistency: '+IntToStr(ConsistencyCheck)+' ---------------------'+#13#10; WriteStr(h); WriteTreeNode(Root,' '); h:='-End-Of-AVL-Tree---------------------'+#13#10; WriteStr(h); end; function TAvgLvlTree.ReportAsString: string; var ms: TMemoryStream; StreamSize: integer; begin Result:=''; ms:=TMemoryStream.Create; try StreamSize:=0; WriteReportToStream(nil,StreamSize); ms.Size:=StreamSize; StreamSize:=0; WriteReportToStream(ms,StreamSize); if ms.Size>0 then begin ms.Position:=0; SetLength(Result,ms.Size); ms.Read(Result[1],ms.Size); end; finally ms.Free; end; end; procedure TAvgLvlTree.SetOnCompare(const AValue: TListSortCompare); var List: PPointer; ANode: TAvgLvlTreeNode; i, OldCount: integer; begin if FOnCompare=AValue then exit; // sort the tree again if Count>0 then begin OldCount:=Count; GetMem(List,SizeOf(Pointer)*OldCount); try // save the data in a list ANode:=FindLowest; i:=0; while ANode<>nil do begin List[i]:=ANode.Data; inc(i); ANode:=FindSuccessor(ANode); end; // clear the tree Clear; // set the new compare function FOnCompare:=AValue; // re-add all nodes for i:=0 to OldCount-1 do Add(List[i]); finally FreeMem(List); end; end; end; { TAvgLvlTreeNode } constructor TAvgLvlTreeNode.Create; begin inherited Create; end; destructor TAvgLvlTreeNode.Destroy; begin inherited Destroy; end; function TAvgLvlTreeNode.TreeDepth: integer; // longest WAY down. e.g. only one node => 0 ! var LeftDepth, RightDepth: integer; begin if Left<>nil then LeftDepth:=Left.TreeDepth+1 else LeftDepth:=0; if Right<>nil then RightDepth:=Right.TreeDepth+1 else RightDepth:=0; if LeftDepth>RightDepth then Result:=LeftDepth else Result:=RightDepth; end; procedure TAvgLvlTreeNode.Clear; begin Parent:=nil; Left:=nil; Right:=nil; Balance:=0; Data:=nil; end; { TAvgLvlTreeNodeMemManager } constructor TAvgLvlTreeNodeMemManager.Create; begin inherited Create; FFirstFree:=nil; FFreeCount:=0; FCount:=0; FMinFree:=100; FMaxFreeRatio:=8; // 1:1 end; destructor TAvgLvlTreeNodeMemManager.Destroy; begin Clear; inherited Destroy; end; procedure TAvgLvlTreeNodeMemManager.DisposeNode(ANode: TAvgLvlTreeNode); begin if ANode=nil then exit; if (FFreeCount(((8+FMaxFreeRatio)*FCount) shr 3)) then begin DisposeFirstFreeNode; DisposeFirstFreeNode; end; end else begin // free list full -> free the ANode ANode.Free; end; dec(FCount); end; function TAvgLvlTreeNodeMemManager.NewNode: TAvgLvlTreeNode; begin if FFirstFree<>nil then begin // take from free list Result:=FFirstFree; FFirstFree:=FFirstFree.Right; Result.Right:=nil; end else begin // free list empty -> create new node Result:=TAvgLvlTreeNode.Create; end; inc(FCount); end; procedure TAvgLvlTreeNodeMemManager.Clear; var ANode: TAvgLvlTreeNode; begin while FFirstFree<>nil do begin ANode:=FFirstFree; FFirstFree:=FFirstFree.Right; ANode.Right:=nil; ANode.Free; end; FFreeCount:=0; end; procedure TAvgLvlTreeNodeMemManager.SetMaxFreeRatio(NewValue: integer); begin if NewValue<0 then NewValue:=0; if NewValue=FMaxFreeRatio then exit; FMaxFreeRatio:=NewValue; end; procedure TAvgLvlTreeNodeMemManager.SetMinFree(NewValue: integer); begin if NewValue<0 then NewValue:=0; if NewValue=FMinFree then exit; FMinFree:=NewValue; end; procedure TAvgLvlTreeNodeMemManager.DisposeFirstFreeNode; var OldNode: TAvgLvlTreeNode; begin if FFirstFree=nil then exit; OldNode:=FFirstFree; FFirstFree:=FFirstFree.Right; dec(FFreeCount); OldNode.Right:=nil; OldNode.Free; end; initialization NodeMemManager:=TAvgLvlTreeNodeMemManager.Create; finalization NodeMemManager.Free; NodeMemManager:=nil; end.