|
@@ -27,6 +27,7 @@ unit AVL_Tree;
|
|
interface
|
|
interface
|
|
|
|
|
|
{off $DEFINE MEM_CHECK}
|
|
{off $DEFINE MEM_CHECK}
|
|
|
|
+{off $DEFINE CheckAVLTreeNodeManager}
|
|
|
|
|
|
uses
|
|
uses
|
|
{$IFDEF MEM_CHECK}MemCheck,{$ENDIF}
|
|
{$IFDEF MEM_CHECK}MemCheck,{$ENDIF}
|
|
@@ -65,7 +66,7 @@ type
|
|
{ TAVLTreeNodeEnumerator }
|
|
{ TAVLTreeNodeEnumerator }
|
|
|
|
|
|
TAVLTreeNodeEnumerator = class
|
|
TAVLTreeNodeEnumerator = class
|
|
- private
|
|
|
|
|
|
+ protected
|
|
FCurrent: TAVLTreeNode;
|
|
FCurrent: TAVLTreeNode;
|
|
FLowToHigh: boolean;
|
|
FLowToHigh: boolean;
|
|
FTree: TAVLTree;
|
|
FTree: TAVLTree;
|
|
@@ -99,6 +100,7 @@ type
|
|
procedure SetOnObjectCompare(const AValue: TObjectSortCompare);
|
|
procedure SetOnObjectCompare(const AValue: TObjectSortCompare);
|
|
procedure SetCompares(const NewCompare: TListSortCompare;
|
|
procedure SetCompares(const NewCompare: TListSortCompare;
|
|
const NewObjectCompare: TObjectSortCompare);
|
|
const NewObjectCompare: TObjectSortCompare);
|
|
|
|
+ procedure SetNodeClass(const AValue: TAVLTreeNodeClass);
|
|
public
|
|
public
|
|
constructor Create(const OnCompareMethod: TListSortCompare);
|
|
constructor Create(const OnCompareMethod: TListSortCompare);
|
|
constructor CreateObjectCompare(const OnCompareMethod: TObjectSortCompare);
|
|
constructor CreateObjectCompare(const OnCompareMethod: TObjectSortCompare);
|
|
@@ -106,7 +108,7 @@ type
|
|
destructor Destroy; override;
|
|
destructor Destroy; override;
|
|
property OnCompare: TListSortCompare read FOnCompare write SetOnCompare;
|
|
property OnCompare: TListSortCompare read FOnCompare write SetOnCompare;
|
|
property OnObjectCompare: TObjectSortCompare read FOnObjectCompare write SetOnObjectCompare;
|
|
property OnObjectCompare: TObjectSortCompare read FOnObjectCompare write SetOnObjectCompare;
|
|
- property NodeClass: TAVLTreeNodeClass read FNodeClass write FNodeClass; // used for new nodes
|
|
|
|
|
|
+ property NodeClass: TAVLTreeNodeClass read FNodeClass write SetNodeClass; // used for new nodes
|
|
procedure SetNodeManager(NewMgr: TBaseAVLTreeNodeManager;
|
|
procedure SetNodeManager(NewMgr: TBaseAVLTreeNodeManager;
|
|
AutoFree: boolean = false);
|
|
AutoFree: boolean = false);
|
|
function NewNode: TAVLTreeNode; virtual; // create a node outside the tree
|
|
function NewNode: TAVLTreeNode; virtual; // create a node outside the tree
|
|
@@ -118,13 +120,13 @@ type
|
|
function AddAscendingSequence(Data: Pointer; LastAdded: TAVLTreeNode;
|
|
function AddAscendingSequence(Data: Pointer; LastAdded: TAVLTreeNode;
|
|
var Successor: TAVLTreeNode): TAVLTreeNode;
|
|
var Successor: TAVLTreeNode): TAVLTreeNode;
|
|
procedure Delete(ANode: TAVLTreeNode);
|
|
procedure Delete(ANode: TAVLTreeNode);
|
|
- procedure Remove(Data: Pointer);
|
|
|
|
- procedure RemovePointer(Data: Pointer);
|
|
|
|
|
|
+ function Remove(Data: Pointer): boolean;
|
|
|
|
+ function RemovePointer(Data: Pointer): boolean;
|
|
procedure MoveDataLeftMost(var ANode: TAVLTreeNode);
|
|
procedure MoveDataLeftMost(var ANode: TAVLTreeNode);
|
|
procedure MoveDataRightMost(var ANode: TAVLTreeNode);
|
|
procedure MoveDataRightMost(var ANode: TAVLTreeNode);
|
|
procedure Clear;
|
|
procedure Clear;
|
|
procedure FreeAndClear;
|
|
procedure FreeAndClear;
|
|
- procedure FreeAndDelete(ANode: TAVLTreeNode);
|
|
|
|
|
|
+ procedure FreeAndDelete(ANode: TAVLTreeNode); virtual;
|
|
function Equals(Obj: TObject): boolean; override; // same as IsEqual(aTree,false)
|
|
function Equals(Obj: TObject): boolean; override; // same as IsEqual(aTree,false)
|
|
function IsEqual(aTree: TAVLTree; CheckDataPointer: boolean): boolean; // checks only keys or Data (references), not the data itself, O(n)
|
|
function IsEqual(aTree: TAVLTree; CheckDataPointer: boolean): boolean; // checks only keys or Data (references), not the data itself, O(n)
|
|
procedure Assign(aTree: TAVLTree); virtual; // clear and copy all Data (references), O(n)
|
|
procedure Assign(aTree: TAVLTree); virtual; // clear and copy all Data (references), O(n)
|
|
@@ -159,7 +161,7 @@ type
|
|
function GetEnumeratorHighToLow: TAVLTreeNodeEnumerator;
|
|
function GetEnumeratorHighToLow: TAVLTreeNodeEnumerator;
|
|
|
|
|
|
// consistency
|
|
// consistency
|
|
- function ConsistencyCheck: integer;
|
|
|
|
|
|
+ procedure ConsistencyCheck; virtual; // JuMa: changed to procedure and added "virtual".
|
|
procedure WriteReportToStream(s: TStream);
|
|
procedure WriteReportToStream(s: TStream);
|
|
function NodeToReportStr(aNode: TAVLTreeNode): string; virtual;
|
|
function NodeToReportStr(aNode: TAVLTreeNode): string; virtual;
|
|
function ReportAsString: string;
|
|
function ReportAsString: string;
|
|
@@ -175,6 +177,9 @@ type
|
|
FCount: SizeInt;
|
|
FCount: SizeInt;
|
|
FMinFree: SizeInt;
|
|
FMinFree: SizeInt;
|
|
FMaxFreeRatio: SizeInt;
|
|
FMaxFreeRatio: SizeInt;
|
|
|
|
+ {$IFDEF CheckAVLTreeNodeManager}
|
|
|
|
+ FThreadId: TThreadID;
|
|
|
|
+ {$ENDIF}
|
|
procedure SetMaxFreeRatio(NewValue: SizeInt);
|
|
procedure SetMaxFreeRatio(NewValue: SizeInt);
|
|
procedure SetMinFree(NewValue: SizeInt);
|
|
procedure SetMinFree(NewValue: SizeInt);
|
|
procedure DisposeFirstFreeNode;
|
|
procedure DisposeFirstFreeNode;
|
|
@@ -235,7 +240,7 @@ end;
|
|
|
|
|
|
function TAVLTree.Add(Data: Pointer): TAVLTreeNode;
|
|
function TAVLTree.Add(Data: Pointer): TAVLTreeNode;
|
|
begin
|
|
begin
|
|
- Result:=fNodeMgr.NewNode;
|
|
|
|
|
|
+ Result:=NewNode;
|
|
Result.Data:=Data;
|
|
Result.Data:=Data;
|
|
Add(Result);
|
|
Add(Result);
|
|
end;
|
|
end;
|
|
@@ -248,8 +253,8 @@ function TAVLTree.AddAscendingSequence(Data: Pointer; LastAdded: TAVLTreeNode;
|
|
For nodes with same value the order of the sequence is kept.
|
|
For nodes with same value the order of the sequence is kept.
|
|
|
|
|
|
Usage:
|
|
Usage:
|
|
- LastNode:=nil; // TAvgLvlTreeNode
|
|
|
|
- Successor:=nil; // TAvgLvlTreeNode
|
|
|
|
|
|
+ LastNode:=nil; // TAvlTreeNode
|
|
|
|
+ Successor:=nil; // TAvlTreeNode
|
|
for i:=1 to 1000 do
|
|
for i:=1 to 1000 do
|
|
LastNode:=Tree.AddAscendingSequence(TItem.Create(i),LastNode,Successor);
|
|
LastNode:=Tree.AddAscendingSequence(TItem.Create(i),LastNode,Successor);
|
|
}
|
|
}
|
|
@@ -283,16 +288,16 @@ end;
|
|
|
|
|
|
function TAVLTree.NewNode: TAVLTreeNode;
|
|
function TAVLTree.NewNode: TAVLTreeNode;
|
|
begin
|
|
begin
|
|
- if NodeMemManager<>nil then
|
|
|
|
- Result:=NodeMemManager.NewNode
|
|
|
|
|
|
+ if fNodeMgr<>nil then
|
|
|
|
+ Result:=fNodeMgr.NewNode
|
|
else
|
|
else
|
|
Result:=NodeClass.Create;
|
|
Result:=NodeClass.Create;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TAVLTree.DisposeNode(ANode: TAVLTreeNode);
|
|
procedure TAVLTree.DisposeNode(ANode: TAVLTreeNode);
|
|
begin
|
|
begin
|
|
- if NodeMemManager<>nil then
|
|
|
|
- NodeMemManager.DisposeNode(ANode)
|
|
|
|
|
|
+ if fNodeMgr<>nil then
|
|
|
|
+ fNodeMgr.DisposeNode(ANode)
|
|
else
|
|
else
|
|
ANode.Free;
|
|
ANode.Free;
|
|
end;
|
|
end;
|
|
@@ -490,6 +495,17 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TAVLTree.SetNodeClass(const AValue: TAVLTreeNodeClass);
|
|
|
|
+begin
|
|
|
|
+ if FNodeClass=AValue then Exit;
|
|
|
|
+ if Count>0 then
|
|
|
|
+ raise Exception.Create(ClassName+'.SetNodeClass Count='+IntToStr(Count)
|
|
|
|
+ +' Old='+fNodeMgr.ClassName+' New='+AValue.ClassName);
|
|
|
|
+ FNodeClass:=AValue;
|
|
|
|
+ if fNodeMgr=NodeMemManager then
|
|
|
|
+ fNodeMgr:=nil;
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TAVLTree.BalanceAfterInsert(ANode: TAVLTreeNode);
|
|
procedure TAVLTree.BalanceAfterInsert(ANode: TAVLTreeNode);
|
|
var
|
|
var
|
|
OldParent, OldRight, OldLeft: TAVLTreeNode;
|
|
OldParent, OldRight, OldLeft: TAVLTreeNode;
|
|
@@ -608,7 +624,7 @@ procedure TAVLTree.Clear;
|
|
if ANode.Left<>nil then DeleteNode(ANode.Left);
|
|
if ANode.Left<>nil then DeleteNode(ANode.Left);
|
|
if ANode.Right<>nil then DeleteNode(ANode.Right);
|
|
if ANode.Right<>nil then DeleteNode(ANode.Right);
|
|
end;
|
|
end;
|
|
- fNodeMgr.DisposeNode(ANode);
|
|
|
|
|
|
+ DisposeNode(ANode);
|
|
end;
|
|
end;
|
|
|
|
|
|
// Clear
|
|
// Clear
|
|
@@ -620,7 +636,6 @@ end;
|
|
|
|
|
|
constructor TAVLTree.Create(const OnCompareMethod: TListSortCompare);
|
|
constructor TAVLTree.Create(const OnCompareMethod: TListSortCompare);
|
|
begin
|
|
begin
|
|
- inherited Create;
|
|
|
|
fNodeMgr:=NodeMemManager;
|
|
fNodeMgr:=NodeMemManager;
|
|
FOnCompare:=OnCompareMethod;
|
|
FOnCompare:=OnCompareMethod;
|
|
Init;
|
|
Init;
|
|
@@ -643,6 +658,12 @@ procedure TAVLTree.Delete(ANode: TAVLTreeNode);
|
|
var
|
|
var
|
|
OldParent, Child: TAVLTreeNode;
|
|
OldParent, Child: TAVLTreeNode;
|
|
begin
|
|
begin
|
|
|
|
+ {$IFDEF CheckAVLTreeNodeManager}
|
|
|
|
+ OldParent:=ANode;
|
|
|
|
+ while OldParent.Parent<>nil do OldParent:=OldParent.Parent;
|
|
|
|
+ if OldParent<>Root then
|
|
|
|
+ raise Exception.Create('TAVLTree.Delete'); // not my node
|
|
|
|
+ {$ENDIF}
|
|
if (ANode.Left<>nil) and (ANode.Right<>nil) then begin
|
|
if (ANode.Left<>nil) and (ANode.Right<>nil) then begin
|
|
// ANode has both: Left and Right
|
|
// ANode has both: Left and Right
|
|
// Switch ANode position with Successor
|
|
// Switch ANode position with Successor
|
|
@@ -679,21 +700,28 @@ begin
|
|
DisposeNode(ANode);
|
|
DisposeNode(ANode);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TAVLTree.Remove(Data: Pointer);
|
|
|
|
-var ANode: TAVLTreeNode;
|
|
|
|
|
|
+function TAVLTree.Remove(Data: Pointer): boolean;
|
|
|
|
+var
|
|
|
|
+ ANode: TAvlTreeNode;
|
|
begin
|
|
begin
|
|
ANode:=Find(Data);
|
|
ANode:=Find(Data);
|
|
- if ANode<>nil then
|
|
|
|
|
|
+ if ANode<>nil then begin
|
|
Delete(ANode);
|
|
Delete(ANode);
|
|
|
|
+ Result:=true;
|
|
|
|
+ end else
|
|
|
|
+ Result:=false;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TAVLTree.RemovePointer(Data: Pointer);
|
|
|
|
|
|
+function TAVLTree.RemovePointer(Data: Pointer): boolean;
|
|
var
|
|
var
|
|
- ANode: TAVLTreeNode;
|
|
|
|
|
|
+ ANode: TAvlTreeNode;
|
|
begin
|
|
begin
|
|
ANode:=FindPointer(Data);
|
|
ANode:=FindPointer(Data);
|
|
- if ANode<>nil then
|
|
|
|
|
|
+ if ANode<>nil then begin
|
|
Delete(ANode);
|
|
Delete(ANode);
|
|
|
|
+ Result:=true;
|
|
|
|
+ end else
|
|
|
|
+ Result:=false;
|
|
end;
|
|
end;
|
|
|
|
|
|
destructor TAVLTree.Destroy;
|
|
destructor TAVLTree.Destroy;
|
|
@@ -1050,7 +1078,8 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TAVLTree.MoveDataLeftMost(var ANode: TAVLTreeNode);
|
|
procedure TAVLTree.MoveDataLeftMost(var ANode: TAVLTreeNode);
|
|
-var LeftMost, PreNode: TAVLTreeNode;
|
|
|
|
|
|
+var
|
|
|
|
+ LeftMost, PreNode: TAVLTreeNode;
|
|
Data: Pointer;
|
|
Data: Pointer;
|
|
begin
|
|
begin
|
|
if ANode=nil then exit;
|
|
if ANode=nil then exit;
|
|
@@ -1068,7 +1097,8 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TAVLTree.MoveDataRightMost(var ANode: TAVLTreeNode);
|
|
procedure TAVLTree.MoveDataRightMost(var ANode: TAVLTreeNode);
|
|
-var RightMost, PostNode: TAVLTreeNode;
|
|
|
|
|
|
+var
|
|
|
|
+ RightMost, PostNode: TAVLTreeNode;
|
|
Data: Pointer;
|
|
Data: Pointer;
|
|
begin
|
|
begin
|
|
if ANode=nil then exit;
|
|
if ANode=nil then exit;
|
|
@@ -1085,7 +1115,7 @@ begin
|
|
ANode:=RightMost;
|
|
ANode:=RightMost;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TAVLTree.ConsistencyCheck: integer;
|
|
|
|
|
|
+procedure TAVLTree.ConsistencyCheck;
|
|
|
|
|
|
procedure E(Msg: string);
|
|
procedure E(Msg: string);
|
|
begin
|
|
begin
|
|
@@ -1095,7 +1125,6 @@ function TAVLTree.ConsistencyCheck: integer;
|
|
var
|
|
var
|
|
RealCount: SizeInt;
|
|
RealCount: SizeInt;
|
|
begin
|
|
begin
|
|
- Result:=0;
|
|
|
|
RealCount:=0;
|
|
RealCount:=0;
|
|
if FRoot<>nil then begin
|
|
if FRoot<>nil then begin
|
|
FRoot.ConsistencyCheck(Self);
|
|
FRoot.ConsistencyCheck(Self);
|
|
@@ -1160,7 +1189,7 @@ begin
|
|
end else begin
|
|
end else begin
|
|
if Compare(MyNode.Data,OtherNode.Data)<>0 then exit;
|
|
if Compare(MyNode.Data,OtherNode.Data)<>0 then exit;
|
|
end;
|
|
end;
|
|
- MyNode:=MyNode.Successor;;
|
|
|
|
|
|
+ MyNode:=MyNode.Successor;
|
|
OtherNode:=OtherNode.Successor;
|
|
OtherNode:=OtherNode.Successor;
|
|
end;
|
|
end;
|
|
if OtherNode<>nil then exit;
|
|
if OtherNode<>nil then exit;
|
|
@@ -1190,7 +1219,7 @@ begin
|
|
if IsEqual(aTree,true) then exit;
|
|
if IsEqual(aTree,true) then exit;
|
|
Clear;
|
|
Clear;
|
|
SetCompares(aTree.OnCompare,aTree.OnObjectCompare);
|
|
SetCompares(aTree.OnCompare,aTree.OnObjectCompare);
|
|
- FNodeClass:=aTree.NodeClass;
|
|
|
|
|
|
+ NodeClass:=aTree.NodeClass;
|
|
if aTree.Root<>nil then
|
|
if aTree.Root<>nil then
|
|
AssignNode(fRoot,aTree.Root);
|
|
AssignNode(fRoot,aTree.Root);
|
|
FCount:=aTree.Count;
|
|
FCount:=aTree.Count;
|
|
@@ -1293,6 +1322,9 @@ procedure TAVLTree.SetNodeManager(NewMgr: TBaseAVLTreeNodeManager;
|
|
AutoFree: boolean);
|
|
AutoFree: boolean);
|
|
// only allowed just after create.
|
|
// only allowed just after create.
|
|
begin
|
|
begin
|
|
|
|
+ if fNodeMgr=NewMgr then exit;
|
|
|
|
+ if Count>0 then
|
|
|
|
+ raise Exception.Create('TAVLTree.SetNodeManager');
|
|
if fNodeMgrAutoFree then
|
|
if fNodeMgrAutoFree then
|
|
FreeAndNil(fNodeMgr);
|
|
FreeAndNil(fNodeMgr);
|
|
fNodeMgr:=NewMgr;
|
|
fNodeMgr:=NewMgr;
|
|
@@ -1407,6 +1439,9 @@ end;
|
|
|
|
|
|
constructor TAVLTreeNodeMemManager.Create;
|
|
constructor TAVLTreeNodeMemManager.Create;
|
|
begin
|
|
begin
|
|
|
|
+ {$IFDEF CheckAVLTreeNodeManager}
|
|
|
|
+ FThreadId:=GetCurrentThreadId;
|
|
|
|
+ {$ENDIF}
|
|
inherited Create;
|
|
inherited Create;
|
|
FFirstFree:=nil;
|
|
FFirstFree:=nil;
|
|
FFreeCount:=0;
|
|
FFreeCount:=0;
|
|
@@ -1424,6 +1459,15 @@ end;
|
|
procedure TAVLTreeNodeMemManager.DisposeNode(ANode: TAVLTreeNode);
|
|
procedure TAVLTreeNodeMemManager.DisposeNode(ANode: TAVLTreeNode);
|
|
begin
|
|
begin
|
|
if ANode=nil then exit;
|
|
if ANode=nil then exit;
|
|
|
|
+ {$IFDEF CheckAVLTreeNodeManager}
|
|
|
|
+ if GetCurrentThreadId<>FThreadId then
|
|
|
|
+ raise Exception.Create('not thread safe!');
|
|
|
|
+ {$ENDIF}
|
|
|
|
+ if FCount < 0 then
|
|
|
|
+ raise Exception.CreateFmt(
|
|
|
|
+ '%s.DisposeNode: FCount (%d) is negative. Should not happen.'
|
|
|
|
+ +' FFreeCount=%d, FMinFree=%d, FMaxFreeRatio=%d.',
|
|
|
|
+ [ClassName, FCount, FFreeCount, FMinFree, FMaxFreeRatio]);
|
|
if (FFreeCount<FMinFree) or (FFreeCount<((FCount shr 3)*FMaxFreeRatio)) then
|
|
if (FFreeCount<FMinFree) or (FFreeCount<((FCount shr 3)*FMaxFreeRatio)) then
|
|
begin
|
|
begin
|
|
// add ANode to Free list
|
|
// add ANode to Free list
|
|
@@ -1444,11 +1488,16 @@ end;
|
|
|
|
|
|
function TAVLTreeNodeMemManager.NewNode: TAVLTreeNode;
|
|
function TAVLTreeNodeMemManager.NewNode: TAVLTreeNode;
|
|
begin
|
|
begin
|
|
|
|
+ {$IFDEF CheckAVLTreeNodeManager}
|
|
|
|
+ if GetCurrentThreadId<>FThreadId then
|
|
|
|
+ raise Exception.Create('not thread safe!');
|
|
|
|
+ {$ENDIF}
|
|
if FFirstFree<>nil then begin
|
|
if FFirstFree<>nil then begin
|
|
// take from free list
|
|
// take from free list
|
|
Result:=FFirstFree;
|
|
Result:=FFirstFree;
|
|
FFirstFree:=FFirstFree.Right;
|
|
FFirstFree:=FFirstFree.Right;
|
|
Result.Right:=nil;
|
|
Result.Right:=nil;
|
|
|
|
+ dec(FFreeCount);
|
|
end else begin
|
|
end else begin
|
|
// free list empty -> create new node
|
|
// free list empty -> create new node
|
|
Result:=TAVLTreeNode.Create;
|
|
Result:=TAVLTreeNode.Create;
|
|
@@ -1459,6 +1508,10 @@ end;
|
|
procedure TAVLTreeNodeMemManager.Clear;
|
|
procedure TAVLTreeNodeMemManager.Clear;
|
|
var ANode: TAVLTreeNode;
|
|
var ANode: TAVLTreeNode;
|
|
begin
|
|
begin
|
|
|
|
+ {$IFDEF CheckAVLTreeNodeManager}
|
|
|
|
+ if GetCurrentThreadId<>FThreadId then
|
|
|
|
+ raise Exception.Create('not thread safe!');
|
|
|
|
+ {$ENDIF}
|
|
while FFirstFree<>nil do begin
|
|
while FFirstFree<>nil do begin
|
|
ANode:=FFirstFree;
|
|
ANode:=FFirstFree;
|
|
FFirstFree:=FFirstFree.Right;
|
|
FFirstFree:=FFirstFree.Right;
|