1{ **********************************************************************
2    This file is part of the Free Component Library (FCL)
3    Copyright (c) 2017 by Mattias Gaertner
4
5    Average Level Tree implementation by Mattias Gaertner
6
7    See the file COPYING.FPC, included in this distribution,
8    for details about the copyright.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14 **********************************************************************
15
16  Author: Mattias Gaertner
17
18  Abstract:
19    TAVLTree is an Average Level binary Tree. This binary tree is always
20    balanced, so that inserting, deleting and finding a node is performed in
21    O(log(#Nodes)).
22
23  Note! This is a copy of avl_tree unit from FPC 3.1.1 from 6th Apr 2017.
24        Can be removed when FPC 3.2 is the minimun requirement for Lazarus and LazUtils.
25}
26unit Laz_AVL_Tree;
27
28{$ifdef FPC}{$mode objfpc}{$endif}{$H+}
29
30interface
31
32{off $DEFINE MEM_CHECK}
33{off $DEFINE CheckAVLTreeNodeManager}
34
35uses
36  {$IFDEF MEM_CHECK}MemCheck,{$ENDIF}
37  Classes, SysUtils;
38
39type
40  TAVLTree = class;
41
42  TObjectSortCompare = function(Tree: TAVLTree; Data1, Data2: Pointer): integer of object;
43
44  { TAVLTreeNode }
45
46  TAVLTreeNode = class
47  public
48    Parent, Left, Right: TAVLTreeNode;
49    Balance: integer; // = RightDepth-LeftDepth  -2..+2, after balancing: -1,0,+1
50    Data: Pointer;
51    function Successor: TAVLTreeNode; // next right
52    function Precessor: TAVLTreeNode; // next left
53    procedure Clear;
54    function TreeDepth: integer; // longest WAY down. e.g. only one node => 0 !
55    procedure ConsistencyCheck(Tree: TAVLTree); virtual;
56    function GetCount: SizeInt;
57  end;
58  TAVLTreeNodeClass = class of TAVLTreeNode;
59  PAVLTreeNode = ^TAVLTreeNode;
60
61  { TBaseAVLTreeNodeManager }
62
63  TBaseAVLTreeNodeManager = class
64  public
65    procedure DisposeNode(ANode: TAVLTreeNode); virtual; abstract;
66    function NewNode: TAVLTreeNode; virtual; abstract;
67  end;
68
69  { TAVLTreeNodeEnumerator }
70
71  TAVLTreeNodeEnumerator = class
72  protected
73    FCurrent: TAVLTreeNode;
74    FLowToHigh: boolean;
75    FTree: TAVLTree;
76  public
77    constructor Create(Tree: TAVLTree; aLowToHigh: boolean = true);
78    function GetEnumerator: TAVLTreeNodeEnumerator; inline;
79    function MoveNext: Boolean;
80    property Current: TAVLTreeNode read FCurrent;
81    property LowToHigh: boolean read FLowToHigh;
82  end;
83
84  TAVLTree = class
85  protected
86    FCount: SizeInt;
87    FNodeClass: TAVLTreeNodeClass;
88    fNodeMgr: TBaseAVLTreeNodeManager;
89    fNodeMgrAutoFree: boolean;
90    FOnCompare: TListSortCompare;
91    FOnObjectCompare: TObjectSortCompare;
92    FRoot: TAVLTreeNode;
93    procedure BalanceAfterInsert(ANode: TAVLTreeNode);
94    procedure BalanceAfterDelete(ANode: TAVLTreeNode);
95    procedure DeletingNode({%H-}aNode: TAVLTreeNode); virtual;
96    function FindInsertPos(Data: Pointer): TAVLTreeNode;
97    procedure Init; virtual;
98    procedure NodeAdded({%H-}aNode: TAVLTreeNode); virtual;
99    procedure RotateLeft(aNode: TAVLTreeNode); virtual;
100    procedure RotateRight(aNode: TAVLTreeNode); virtual;
101    procedure SwitchPositionWithSuccessor(aNode, aSuccessor: TAVLTreeNode); virtual;
102    procedure SetOnCompare(const AValue: TListSortCompare);
103    procedure SetOnObjectCompare(const AValue: TObjectSortCompare);
104    procedure SetCompares(const NewCompare: TListSortCompare;
105                          const NewObjectCompare: TObjectSortCompare);
106    procedure SetNodeClass(const AValue: TAVLTreeNodeClass);
107  public
108    constructor Create(const OnCompareMethod: TListSortCompare);
109    constructor CreateObjectCompare(const OnCompareMethod: TObjectSortCompare);
110    constructor Create;
111    destructor Destroy; override;
112    property OnCompare: TListSortCompare read FOnCompare write SetOnCompare;
113    property OnObjectCompare: TObjectSortCompare read FOnObjectCompare write SetOnObjectCompare;
114    property NodeClass: TAVLTreeNodeClass read FNodeClass write SetNodeClass; // used for new nodes
115    procedure SetNodeManager(NewMgr: TBaseAVLTreeNodeManager;
116                             AutoFree: boolean = false);
117    function NewNode: TAVLTreeNode; virtual; // create a node outside the tree
118    procedure DisposeNode(ANode: TAVLTreeNode); virtual; // free the node outside the tree
119
120    // add, delete, remove, move
121    procedure Add(ANode: TAVLTreeNode);
122    function Add(Data: Pointer): TAVLTreeNode;
123    function AddAscendingSequence(Data: Pointer; LastAdded: TAVLTreeNode;
124      var Successor: TAVLTreeNode): TAVLTreeNode;
125    procedure Delete(ANode: TAVLTreeNode);
126    // JuMa: Turned Remove and RemovePointer into functions.
127    function Remove(Data: Pointer): boolean;
128    function RemovePointer(Data: Pointer): boolean;
129    procedure MoveDataLeftMost(var ANode: TAVLTreeNode);
130    procedure MoveDataRightMost(var ANode: TAVLTreeNode);
131    procedure Clear;
132    procedure FreeAndClear;
133    procedure FreeAndDelete(ANode: TAVLTreeNode); virtual;
134    function Equals(Obj: TObject): boolean; override; // same as IsEqual(aTree,false)
135    function IsEqual(aTree: TAVLTree; CheckDataPointer: boolean): boolean; // checks only keys or Data (references), not the data itself, O(n)
136    procedure Assign(aTree: TAVLTree); virtual; // clear and copy all Data (references), O(n)
137
138    // search
139    property Root: TAVLTreeNode read fRoot;
140    property Count: SizeInt read FCount;
141    function Compare(Data1, Data2: Pointer): integer;
142    function Find(Data: Pointer): TAVLTreeNode; // O(log(n))
143    function FindKey(Key: Pointer;
144      const OnCompareKeyWithData: TListSortCompare): TAVLTreeNode; // O(log(n))
145    function FindNearestKey(Key: Pointer;
146      const OnCompareKeyWithData: TListSortCompare): TAVLTreeNode; // O(log(n))
147    function FindSuccessor(ANode: TAVLTreeNode): TAVLTreeNode; inline;
148    function FindPrecessor(ANode: TAVLTreeNode): TAVLTreeNode; inline;
149    function FindLowest: TAVLTreeNode; // O(log(n))
150    function FindHighest: TAVLTreeNode; // O(log(n))
151    function FindNearest(Data: Pointer): TAVLTreeNode;
152    // search in a tree with duplicates (duplicate means here: Compare function returns 0)
153    function FindPointer(Data: Pointer): TAVLTreeNode;
154    function FindLeftMost(Data: Pointer): TAVLTreeNode;
155    function FindRightMost(Data: Pointer): TAVLTreeNode;
156    function FindLeftMostKey(Key: Pointer;
157      const OnCompareKeyWithData: TListSortCompare): TAVLTreeNode;
158    function FindRightMostKey(Key: Pointer;
159      const OnCompareKeyWithData: TListSortCompare): TAVLTreeNode;
160    function FindLeftMostSameKey(ANode: TAVLTreeNode): TAVLTreeNode;
161    function FindRightMostSameKey(ANode: TAVLTreeNode): TAVLTreeNode;
162
163    // enumerators
164    function GetEnumerator: TAVLTreeNodeEnumerator;
165    function GetEnumeratorHighToLow: TAVLTreeNodeEnumerator;
166
167    // consistency
168    procedure ConsistencyCheck; virtual; // JuMa: changed to procedure and added "virtual".
169    procedure WriteReportToStream(s: TStream);
170    function NodeToReportStr(aNode: TAVLTreeNode): string; virtual;
171    function ReportAsString: string;
172  end;
173  TAVLTreeClass = class of TAVLTree;
174
175  { TAVLTreeNodeMemManager }
176
177  TAVLTreeNodeMemManager = class(TBaseAVLTreeNodeManager)
178  private
179    FFirstFree: TAVLTreeNode;
180    FFreeCount: SizeInt;
181    FCount: SizeInt;
182    FMinFree: SizeInt;
183    FMaxFreeRatio: SizeInt;
184    {$IFDEF CheckAVLTreeNodeManager}
185    FThreadId: TThreadID;
186    {$ENDIF}
187    procedure SetMaxFreeRatio(NewValue: SizeInt);
188    procedure SetMinFree(NewValue: SizeInt);
189    procedure DisposeFirstFreeNode;
190  public
191    procedure DisposeNode(ANode: TAVLTreeNode); override;
192    function NewNode: TAVLTreeNode; override;
193    property MinimumFreeNode: SizeInt read FMinFree write SetMinFree;
194    property MaximumFreeNodeRatio: SizeInt
195        read FMaxFreeRatio write SetMaxFreeRatio; // in one eighth steps
196    property Count: SizeInt read FCount;
197    procedure Clear;
198    constructor Create;
199    destructor Destroy; override;
200  end;
201
202var
203  LazNodeMemManager: TAVLTreeNodeMemManager;
204
205implementation
206
207function ComparePointer(Data1, Data2: Pointer): integer;
208begin
209  if Data1>Data2 then Result:=-1
210  else if Data1<Data2 then Result:=1
211  else Result:=0;
212end;
213
214{ TAVLTreeNodeEnumerator }
215
216constructor TAVLTreeNodeEnumerator.Create(Tree: TAVLTree; aLowToHigh: boolean);
217begin
218  FTree:=Tree;
219  FLowToHigh:=aLowToHigh;
220end;
221
222function TAVLTreeNodeEnumerator.GetEnumerator: TAVLTreeNodeEnumerator;
223begin
224  Result:=Self;
225end;
226
227function TAVLTreeNodeEnumerator.MoveNext: Boolean;
228begin
229  if FLowToHigh then begin
230    if FCurrent<>nil then
231      FCurrent:=FCurrent.Successor
232    else
233      FCurrent:=FTree.FindLowest;
234  end else begin
235    if FCurrent<>nil then
236      FCurrent:=FCurrent.Precessor
237    else
238      FCurrent:=FTree.FindHighest;
239  end;
240  Result:=FCurrent<>nil;
241end;
242
243{ TAVLTree }
244
245function TAVLTree.Add(Data: Pointer): TAVLTreeNode;
246begin
247  Result:=NewNode;
248  Result.Data:=Data;
249  Add(Result);
250end;
251
252function TAVLTree.AddAscendingSequence(Data: Pointer; LastAdded: TAVLTreeNode;
253  var Successor: TAVLTreeNode): TAVLTreeNode;
254{ This is an optimized version of "Add" for adding an ascending sequence of
255  nodes.
256  It uses the LastAdded and Successor to skip searching for an insert position.
257  For nodes with same value the order of the sequence is kept.
258
259  Usage:
260    LastNode:=nil; // TAvlTreeNode
261    Successor:=nil; // TAvlTreeNode
262    for i:=1 to 1000 do
263      LastNode:=Tree.AddAscendingSequence(TItem.Create(i),LastNode,Successor);
264}
265var
266  InsertPos: TAVLTreeNode;
267begin
268  Result:=NewNode;
269  Result.Data:=Data;
270  if (LastAdded<>nil) and (Compare(LastAdded.Data,Data)<=0)
271  and ((Successor=nil) or (Compare(Data,Successor.Data)<=0)) then begin
272    // Data is between LastAdded and Successor
273    inc(FCount);
274    if LastAdded.Right=nil then begin
275      Result.Parent:=LastAdded;
276      LastAdded.Right:=Result;
277    end else begin
278      InsertPos:=LastAdded.Right;
279      while InsertPos.Left<>nil do
280        InsertPos:=InsertPos.Left;
281      Result.Parent:=InsertPos;
282      InsertPos.Left:=Result;
283    end;
284    NodeAdded(Result);
285    BalanceAfterInsert(Result);
286  end else begin
287    // normal Add
288    Add(Result);
289    Successor:=Result.Successor;
290  end;
291end;
292
293function TAVLTree.NewNode: TAVLTreeNode;
294begin
295  if fNodeMgr<>nil then
296    Result:=fNodeMgr.NewNode
297  else
298    Result:=NodeClass.Create;
299end;
300
301procedure TAVLTree.DisposeNode(ANode: TAVLTreeNode);
302begin
303  if fNodeMgr<>nil then
304    fNodeMgr.DisposeNode(ANode)
305  else
306    ANode.Free;
307end;
308
309procedure TAVLTree.Add(ANode: TAVLTreeNode);
310// add a node. If there are already nodes with the same value it will be
311// inserted rightmost
312var InsertPos: TAVLTreeNode;
313  InsertComp: integer;
314begin
315  ANode.Left:=nil;
316  ANode.Right:=nil;
317  inc(FCount);
318  if Root<>nil then begin
319    InsertPos:=FindInsertPos(ANode.Data);
320    InsertComp:=Compare(ANode.Data,InsertPos.Data);
321    ANode.Parent:=InsertPos;
322    if InsertComp<0 then begin
323      // insert to the left
324      InsertPos.Left:=ANode;
325    end else begin
326      // insert to the right
327      InsertPos.Right:=ANode;
328    end;
329    NodeAdded(ANode);
330    BalanceAfterInsert(ANode);
331  end else begin
332    fRoot:=ANode;
333    ANode.Parent:=nil;
334    NodeAdded(ANode);
335  end;
336end;
337
338function TAVLTree.FindLowest: TAVLTreeNode;
339begin
340  Result:=Root;
341  if Result<>nil then
342    while Result.Left<>nil do Result:=Result.Left;
343end;
344
345function TAVLTree.FindHighest: TAVLTreeNode;
346begin
347  Result:=Root;
348  if Result<>nil then
349    while Result.Right<>nil do Result:=Result.Right;
350end;
351
352procedure TAVLTree.BalanceAfterDelete(ANode: TAVLTreeNode);
353var
354  OldParent, OldRight, OldRightLeft, OldLeft, OldLeftRight: TAVLTreeNode;
355begin
356  while ANode<>nil do begin
357    if ((ANode.Balance=+1) or (ANode.Balance=-1)) then exit;
358    OldParent:=ANode.Parent;
359    if (ANode.Balance=0) then begin
360      // Treeheight has decreased by one
361      if (OldParent=nil) then
362        exit;
363      if(OldParent.Left=ANode) then
364        Inc(OldParent.Balance)
365      else
366        Dec(OldParent.Balance);
367      ANode:=OldParent;
368    end else if (ANode.Balance=+2) then begin
369      // Node is overweighted to the right
370      OldRight:=ANode.Right;
371      if (OldRight.Balance>=0) then begin
372        // OldRight.Balance is 0 or -1
373        // rotate ANode,OldRight left
374        RotateLeft(ANode);
375        ANode.Balance:=(1-OldRight.Balance); // toggle 0 and 1
376        Dec(OldRight.Balance);
377        ANode:=OldRight;
378      end else begin
379        // OldRight.Balance=-1
380        { double rotate
381          = rotate OldRightLeft,OldRight right
382            and then rotate ANode,OldRightLeft left
383                  OldParent                           OldParent
384                      |                                  |
385                    ANode                           OldRightLeft
386                       \                               /      \
387                    OldRight             =>          ANode    OldRight
388                      /                                \         /
389               OldRightLeft                OldRightLeftLeft OldRightLeftRight
390                   /     \
391        OldRightLeftLeft OldRightLeftRight
392        }
393        OldRightLeft:=OldRight.Left;
394        RotateRight(OldRight);
395        RotateLeft(ANode);
396        if (OldRightLeft.Balance<=0) then
397          ANode.Balance:=0
398        else
399          ANode.Balance:=-1;
400        if (OldRightLeft.Balance>=0) then
401          OldRight.Balance:=0
402        else
403          OldRight.Balance:=+1;
404        OldRightLeft.Balance:=0;
405        ANode:=OldRightLeft;
406      end;
407    end else begin
408      // Node.Balance=-2
409      // Node is overweighted to the left
410      OldLeft:=ANode.Left;
411      if (OldLeft.Balance<=0) then begin
412        // rotate OldLeft,ANode right
413        RotateRight(ANode);
414        ANode.Balance:=(-1-OldLeft.Balance); // toggle 0 and -1
415        Inc(OldLeft.Balance);
416        ANode:=OldLeft;
417      end else begin
418        // OldLeft.Balance = 1
419        { double rotate left right
420          = rotate OldLeft,OldLeftRight left
421            and then rotate OldLeft,ANode right
422                    OldParent                           OldParent
423                        |                                  |
424                      ANode                            OldLeftRight
425                       /                               /         \
426                    OldLeft             =>          OldLeft    ANode
427                       \                                \         /
428                   OldLeftRight               OldLeftRightLeft OldLeftRightRight
429                     /     \
430          OldLeftRightLeft OldLeftRightRight
431        }
432        OldLeftRight:=OldLeft.Right;
433        RotateLeft(OldLeft);
434        RotateRight(ANode);
435        if (OldLeftRight.Balance>=0) then
436          ANode.Balance:=0
437        else
438          ANode.Balance:=+1;
439        if (OldLeftRight.Balance<=0) then
440          OldLeft.Balance:=0
441        else
442          OldLeft.Balance:=-1;
443        OldLeftRight.Balance:=0;
444        ANode:=OldLeftRight;
445      end;
446    end;
447  end;
448end;
449
450procedure TAVLTree.DeletingNode(aNode: TAVLTreeNode);
451// called by Delete
452// Node.Left=nil or Node.Right=nil
453begin
454  // for descendants to override
455end;
456
457procedure TAVLTree.SetOnObjectCompare(const AValue: TObjectSortCompare);
458begin
459  if AValue=nil then
460    SetCompares(FOnCompare,nil)
461  else
462    SetCompares(nil,AValue);
463end;
464
465procedure TAVLTree.SetCompares(const NewCompare: TListSortCompare;
466  const NewObjectCompare: TObjectSortCompare);
467var List: PPointer;
468  ANode: TAVLTreeNode;
469  i, OldCount: integer;
470begin
471  if (FOnCompare=NewCompare) and (FOnObjectCompare=NewObjectCompare) then exit;
472  if Count<=1 then begin
473    FOnCompare:=NewCompare;
474    FOnObjectCompare:=NewObjectCompare;
475    exit;
476  end;
477  // sort the tree again
478  OldCount:=Count;
479  GetMem(List,SizeOf(Pointer)*OldCount);
480  try
481    // save the data in a list
482    ANode:=FindLowest;
483    i:=0;
484    while ANode<>nil do begin
485      List[i]:=ANode.Data;
486      inc(i);
487      ANode:=ANode.Successor;
488    end;
489    // clear the tree
490    Clear;
491    // set the new compare function
492    FOnCompare:=NewCompare;
493    FOnObjectCompare:=NewObjectCompare;
494    // re-add all nodes
495    for i:=0 to OldCount-1 do
496      Add(List[i]);
497  finally
498    FreeMem(List);
499  end;
500end;
501
502procedure TAVLTree.SetNodeClass(const AValue: TAVLTreeNodeClass);
503begin
504  if FNodeClass=AValue then Exit;
505  if Count>0 then
506    raise Exception.Create(ClassName+'.SetNodeClass Count='+IntToStr(Count)
507      +' Old='+fNodeMgr.ClassName+' New='+AValue.ClassName);
508  FNodeClass:=AValue;
509  if fNodeMgr=LazNodeMemManager then
510    fNodeMgr:=nil;
511end;
512
513procedure TAVLTree.BalanceAfterInsert(ANode: TAVLTreeNode);
514var
515  OldParent, OldRight, OldLeft: TAVLTreeNode;
516begin
517  OldParent:=ANode.Parent;
518  while (OldParent<>nil) do begin
519    if (OldParent.Left=ANode) then begin
520      // Node is left child
521      dec(OldParent.Balance);
522      if (OldParent.Balance=0) then exit;
523      if (OldParent.Balance=-1) then begin
524        ANode:=OldParent;
525        OldParent:=ANode.Parent;
526        continue;
527      end;
528      // OldParent.Balance=-2
529      if (ANode.Balance=-1) then begin
530        { rotate ANode,ANode.Parent right
531             OldParentParent        OldParentParent
532                   |                     |
533               OldParent        =>     ANode
534                 /                        \
535              ANode                     OldParent
536                \                        /
537              OldRight               OldRight      }
538        RotateRight(OldParent);
539        ANode.Balance:=0;
540        OldParent.Balance:=0;
541      end else begin
542        // Node.Balance = +1
543        { double rotate
544          = rotate ANode,OldRight left and then rotate OldRight,OldParent right
545             OldParentParent             OldParentParent
546                    |                           |
547                OldParent                    OldRight
548                   /            =>          /        \
549                 ANode                   ANode      OldParent
550                    \                       \          /
551                   OldRight          OldRightLeft  OldRightRight
552                     / \
553          OldRightLeft OldRightRight
554        }
555        OldRight:=ANode.Right;
556        RotateLeft(ANode);
557        RotateRight(OldParent);
558        if (OldRight.Balance<=0) then
559          ANode.Balance:=0
560        else
561          ANode.Balance:=-1;
562        if (OldRight.Balance=-1) then
563          OldParent.Balance:=1
564        else
565          OldParent.Balance:=0;
566        OldRight.Balance:=0;
567      end;
568      exit;
569    end else begin
570      // Node is right child
571      Inc(OldParent.Balance);
572      if (OldParent.Balance=0) then exit;
573      if (OldParent.Balance=+1) then begin
574        ANode:=OldParent;
575        OldParent:=ANode.Parent;
576        continue;
577      end;
578      // OldParent.Balance = +2
579      if(ANode.Balance=+1) then begin
580        { rotate OldParent,ANode left
581             OldParentParent        OldParentParent
582                   |                     |
583               OldParent        =>     ANode
584                    \                   /
585                  ANode               OldParent
586                   /                      \
587                OldLeft                 OldLeft      }
588        RotateLeft(OldParent);
589        ANode.Balance:=0;
590        OldParent.Balance:=0;
591      end else begin
592        // Node.Balance = -1
593        { double rotate
594          = rotate OldLeft,ANode right and then rotate OldParent,OldLeft right
595             OldParentParent             OldParentParent
596                    |                           |
597                OldParent                    OldLeft
598                     \            =>        /       \
599                    ANode               OldParent   ANode
600                     /                     \          /
601                  OldLeft          OldLeftLeft  OldLeftRight
602                    / \
603         OldLeftLeft OldLeftRight
604        }
605        OldLeft:=ANode.Left;
606        RotateRight(ANode);
607        RotateLeft(OldParent);
608        if (OldLeft.Balance>=0) then
609          ANode.Balance:=0
610        else
611          ANode.Balance:=+1;
612        if (OldLeft.Balance=+1) then
613          OldParent.Balance:=-1
614        else
615          OldParent.Balance:=0;
616        OldLeft.Balance:=0;
617      end;
618      exit;
619    end;
620  end;
621end;
622
623procedure TAVLTree.Clear;
624
625  procedure DeleteNode(ANode: TAVLTreeNode);
626  begin
627    if ANode.Left<>nil then DeleteNode(ANode.Left);
628    if ANode.Right<>nil then DeleteNode(ANode.Right);
629    DisposeNode(ANode);
630  end;
631
632// Clear
633begin
634  if Root<>nil then
635    DeleteNode(Root);
636  fRoot:=nil;
637  FCount:=0;
638end;
639
640constructor TAVLTree.Create(const OnCompareMethod: TListSortCompare);
641begin
642  FOnCompare:=OnCompareMethod;
643  Init;
644end;
645
646constructor TAVLTree.CreateObjectCompare(
647  const OnCompareMethod: TObjectSortCompare);
648begin
649  FOnObjectCompare:=OnCompareMethod;
650  Init;
651end;
652
653constructor TAVLTree.Create;
654begin
655  Create(@ComparePointer);
656end;
657
658procedure TAVLTree.Delete(ANode: TAVLTreeNode);
659var
660  OldParent, Child: TAVLTreeNode;
661begin
662  {$IFDEF CheckAVLTreeNodeManager}
663  OldParent:=ANode;
664  while OldParent.Parent<>nil do OldParent:=OldParent.Parent;
665  if OldParent<>Root then
666    raise Exception.Create('TAVLTree.Delete'); // not my node
667  {$ENDIF}
668  if (ANode.Left<>nil) and (ANode.Right<>nil) then begin
669    // ANode has both: Left and Right
670    // Switch ANode position with Successor
671    // Because ANode.Right<>nil the Successor is a child of ANode
672    SwitchPositionWithSuccessor(ANode,ANode.Successor);
673  end;
674  // left or right is nil
675  DeletingNode(aNode);
676  OldParent:=ANode.Parent;
677  ANode.Parent:=nil;
678  if ANode.Left<>nil then
679    Child:=ANode.Left
680  else
681    Child:=ANode.Right;
682  if Child<>nil then
683    Child.Parent:=OldParent;
684  if (OldParent<>nil) then begin
685    // Node has parent
686    if (OldParent.Left=ANode) then begin
687      // Node is left child of OldParent
688      OldParent.Left:=Child;
689      Inc(OldParent.Balance);
690    end else begin
691      // Node is right child of OldParent
692      OldParent.Right:=Child;
693      Dec(OldParent.Balance);
694    end;
695    BalanceAfterDelete(OldParent);
696  end else begin
697    // Node was Root
698    fRoot:=Child;
699  end;
700  dec(FCount);
701  DisposeNode(ANode);
702end;
703
704function TAVLTree.Remove(Data: Pointer): boolean;
705var
706  ANode: TAvlTreeNode;
707begin
708  ANode:=Find(Data);
709  if ANode<>nil then begin
710    Delete(ANode);
711    Result:=true;
712  end else
713    Result:=false;
714end;
715
716function TAVLTree.RemovePointer(Data: Pointer): boolean;
717var
718  ANode: TAvlTreeNode;
719begin
720  ANode:=FindPointer(Data);
721  if ANode<>nil then begin
722    Delete(ANode);
723    Result:=true;
724  end else
725    Result:=false;
726end;
727
728destructor TAVLTree.Destroy;
729begin
730  Clear;
731  if fNodeMgrAutoFree then
732    FreeAndNil(fNodeMgr);
733  inherited Destroy;
734end;
735
736function TAVLTree.GetEnumerator: TAVLTreeNodeEnumerator;
737begin
738  Result:=TAVLTreeNodeEnumerator.Create(Self,true);
739end;
740
741function TAVLTree.GetEnumeratorHighToLow: TAVLTreeNodeEnumerator;
742begin
743  Result:=TAVLTreeNodeEnumerator.Create(Self,false);
744end;
745
746function TAVLTree.Find(Data: Pointer): TAVLTreeNode;
747var Comp: integer;
748begin
749  Result:=Root;
750  while (Result<>nil) do begin
751    Comp:=Compare(Data,Result.Data);
752    if Comp=0 then exit;
753    if Comp<0 then begin
754      Result:=Result.Left
755    end else begin
756      Result:=Result.Right
757    end;
758  end;
759end;
760
761function TAVLTree.FindKey(Key: Pointer; const OnCompareKeyWithData: TListSortCompare
762  ): TAVLTreeNode;
763var Comp: integer;
764begin
765  Result:=Root;
766  while (Result<>nil) do begin
767    Comp:=OnCompareKeyWithData(Key,Result.Data);
768    if Comp=0 then exit;
769    if Comp<0 then begin
770      Result:=Result.Left
771    end else begin
772      Result:=Result.Right
773    end;
774  end;
775end;
776
777function TAVLTree.FindNearestKey(Key: Pointer;
778  const OnCompareKeyWithData: TListSortCompare): TAVLTreeNode;
779var Comp: integer;
780begin
781  Result:=fRoot;
782  while (Result<>nil) do begin
783    Comp:=OnCompareKeyWithData(Key,Result.Data);
784    if Comp=0 then exit;
785    if Comp<0 then begin
786      if Result.Left<>nil then
787        Result:=Result.Left
788      else
789        exit;
790    end else begin
791      if Result.Right<>nil then
792        Result:=Result.Right
793      else
794        exit;
795    end;
796  end;
797end;
798
799function TAVLTree.FindLeftMostKey(Key: Pointer;
800  const OnCompareKeyWithData: TListSortCompare): TAVLTreeNode;
801var
802  LeftNode: TAVLTreeNode;
803begin
804  Result:=FindKey(Key,OnCompareKeyWithData);
805  if Result=nil then exit;
806  repeat
807    LeftNode:=Result.Precessor;
808    if (LeftNode=nil) or (OnCompareKeyWithData(Key,LeftNode.Data)<>0) then exit;
809    Result:=LeftNode;
810  until false;
811end;
812
813function TAVLTree.FindRightMostKey(Key: Pointer;
814  const OnCompareKeyWithData: TListSortCompare): TAVLTreeNode;
815var
816  RightNode: TAVLTreeNode;
817begin
818  Result:=FindKey(Key,OnCompareKeyWithData);
819  if Result=nil then exit;
820  repeat
821    RightNode:=Result.Successor;
822    if (RightNode=nil) or (OnCompareKeyWithData(Key,RightNode.Data)<>0) then exit;
823    Result:=RightNode;
824  until false;
825end;
826
827function TAVLTree.FindLeftMostSameKey(ANode: TAVLTreeNode): TAVLTreeNode;
828var
829  LeftNode: TAVLTreeNode;
830  Data: Pointer;
831begin
832  if ANode<>nil then begin
833    Data:=ANode.Data;
834    Result:=ANode;
835    repeat
836      LeftNode:=Result.Precessor;
837      if (LeftNode=nil) or (Compare(Data,LeftNode.Data)<>0) then break;
838      Result:=LeftNode;
839    until false;
840  end else begin
841    Result:=nil;
842  end;
843end;
844
845function TAVLTree.FindRightMostSameKey(ANode: TAVLTreeNode): TAVLTreeNode;
846var
847  RightNode: TAVLTreeNode;
848  Data: Pointer;
849begin
850  if ANode<>nil then begin
851    Data:=ANode.Data;
852    Result:=ANode;
853    repeat
854      RightNode:=Result.Successor;
855      if (RightNode=nil) or (Compare(Data,RightNode.Data)<>0) then break;
856      Result:=RightNode;
857    until false;
858  end else begin
859    Result:=nil;
860  end;
861end;
862
863function TAVLTree.FindNearest(Data: Pointer): TAVLTreeNode;
864var Comp: integer;
865begin
866  Result:=Root;
867  while (Result<>nil) do begin
868    Comp:=Compare(Data,Result.Data);
869    if Comp=0 then exit;
870    if Comp<0 then begin
871      if Result.Left<>nil then
872        Result:=Result.Left
873      else
874        exit;
875    end else begin
876      if Result.Right<>nil then
877        Result:=Result.Right
878      else
879        exit;
880    end;
881  end;
882end;
883
884function TAVLTree.FindPointer(Data: Pointer): TAVLTreeNode;
885// same as Find, but not comparing for key, but same Data too
886begin
887  Result:=FindLeftMost(Data);
888  while (Result<>nil) do begin
889    if Result.Data=Data then break;
890    Result:=Result.Successor;
891    if Result=nil then exit;
892    if Compare(Data,Result.Data)<>0 then exit(nil);
893  end;
894end;
895
896function TAVLTree.FindLeftMost(Data: Pointer): TAVLTreeNode;
897var
898  Left: TAVLTreeNode;
899begin
900  Result:=Find(Data);
901  while (Result<>nil) do begin
902    Left:=Result.Precessor;
903    if (Left=nil) or (Compare(Data,Left.Data)<>0) then break;
904    Result:=Left;
905  end;
906end;
907
908function TAVLTree.FindRightMost(Data: Pointer): TAVLTreeNode;
909var
910  Right: TAVLTreeNode;
911begin
912  Result:=Find(Data);
913  while (Result<>nil) do begin
914    Right:=Result.Successor;
915    if (Right=nil) or (Compare(Data,Right.Data)<>0) then break;
916    Result:=Right;
917  end;
918end;
919
920function TAVLTree.FindInsertPos(Data: Pointer): TAVLTreeNode;
921var Comp: integer;
922begin
923  Result:=Root;
924  while (Result<>nil) do begin
925    Comp:=Compare(Data,Result.Data);
926    if Comp<0 then begin
927      if Result.Left<>nil then
928        Result:=Result.Left
929      else
930        exit;
931    end else begin
932      if Result.Right<>nil then
933        Result:=Result.Right
934      else
935        exit;
936    end;
937  end;
938end;
939
940procedure TAVLTree.Init;
941begin
942  FNodeClass:=TAVLTreeNode;
943end;
944
945procedure TAVLTree.NodeAdded(aNode: TAVLTreeNode);
946begin
947  // for descendants to override
948end;
949
950procedure TAVLTree.RotateLeft(aNode: TAVLTreeNode);
951{    Parent                Parent
952       |                     |
953      Node        =>       OldRight
954      /  \                  /
955   Left OldRight          Node
956          /               /  \
957     OldRightLeft      Left OldRightLeft  }
958var
959  AParent, OldRight, OldRightLeft: TAVLTreeNode;
960begin
961  OldRight:=aNode.Right;
962  OldRightLeft:=OldRight.Left;
963  AParent:=aNode.Parent;
964  if AParent<>nil then begin
965    if AParent.Left=aNode then
966      AParent.Left:=OldRight
967    else
968      AParent.Right:=OldRight;
969  end else
970    fRoot:=OldRight;
971  OldRight.Parent:=AParent;
972  aNode.Parent:=OldRight;
973  aNode.Right:=OldRightLeft;
974  if OldRightLeft<>nil then
975    OldRightLeft.Parent:=aNode;
976  OldRight.Left:=aNode;
977end;
978
979procedure TAVLTree.RotateRight(aNode: TAVLTreeNode);
980{       Parent              Parent
981          |                   |
982         Node        =>     OldLeft
983         /   \                 \
984    OldLeft  Right            Node
985        \                     /  \
986   OldLeftRight      OldLeftRight Right  }
987var
988  AParent, OldLeft, OldLeftRight: TAVLTreeNode;
989begin
990  OldLeft:=aNode.Left;
991  OldLeftRight:=OldLeft.Right;
992  AParent:=aNode.Parent;
993  if AParent<>nil then begin
994    if AParent.Left=aNode then
995      AParent.Left:=OldLeft
996    else
997      AParent.Right:=OldLeft;
998  end else
999    fRoot:=OldLeft;
1000  OldLeft.Parent:=AParent;
1001  aNode.Parent:=OldLeft;
1002  aNode.Left:=OldLeftRight;
1003  if OldLeftRight<>nil then
1004    OldLeftRight.Parent:=aNode;
1005  OldLeft.Right:=aNode;
1006end;
1007
1008procedure TAVLTree.SwitchPositionWithSuccessor(aNode, aSuccessor: TAVLTreeNode);
1009{ called by delete, when aNode.Left<>nil and aNode.Right<>nil
1010  Switch ANode position with Successor
1011  Because ANode.Right<>nil the Successor is a child of ANode }
1012var
1013  OldBalance: Integer;
1014  OldParent, OldLeft, OldRight,
1015  OldSuccParent, OldSuccLeft, OldSuccRight: TAVLTreeNode;
1016begin
1017  OldBalance:=aNode.Balance;
1018  aNode.Balance:=aSuccessor.Balance;
1019  aSuccessor.Balance:=OldBalance;
1020
1021  OldParent:=aNode.Parent;
1022  OldLeft:=aNode.Left;
1023  OldRight:=aNode.Right;
1024  OldSuccParent:=aSuccessor.Parent;
1025  OldSuccLeft:=aSuccessor.Left;
1026  OldSuccRight:=aSuccessor.Right;
1027
1028  if OldParent<>nil then begin
1029    if OldParent.Left=aNode then
1030      OldParent.Left:=aSuccessor
1031    else
1032      OldParent.Right:=aSuccessor;
1033  end else
1034    fRoot:=aSuccessor;
1035  aSuccessor.Parent:=OldParent;
1036
1037  if OldSuccParent<>aNode then begin
1038    if OldSuccParent.Left=aSuccessor then
1039      OldSuccParent.Left:=aNode
1040    else
1041      OldSuccParent.Right:=aNode;
1042    aSuccessor.Right:=OldRight;
1043    aNode.Parent:=OldSuccParent;
1044    if OldRight<>nil then
1045      OldRight.Parent:=aSuccessor;
1046  end else begin
1047    {  aNode            aSuccessor
1048         \          =>    \
1049         aSuccessor       aNode  }
1050    aSuccessor.Right:=aNode;
1051    aNode.Parent:=aSuccessor;
1052  end;
1053
1054  aNode.Left:=OldSuccLeft;
1055  if OldSuccLeft<>nil then
1056    OldSuccLeft.Parent:=aNode;
1057  aNode.Right:=OldSuccRight;
1058  if OldSuccRight<>nil then
1059    OldSuccRight.Parent:=aNode;
1060  aSuccessor.Left:=OldLeft;
1061  if OldLeft<>nil then
1062    OldLeft.Parent:=aSuccessor;
1063end;
1064
1065function TAVLTree.FindSuccessor(ANode: TAVLTreeNode): TAVLTreeNode;
1066begin
1067  if ANode<>nil then
1068    Result:=ANode.Successor
1069  else
1070    Result:=nil;
1071end;
1072
1073function TAVLTree.FindPrecessor(ANode: TAVLTreeNode): TAVLTreeNode;
1074begin
1075  if ANode<>nil then
1076    Result:=ANode.Precessor
1077  else
1078    Result:=nil;
1079end;
1080
1081procedure TAVLTree.MoveDataLeftMost(var ANode: TAVLTreeNode);
1082var
1083  LeftMost, PreNode: TAVLTreeNode;
1084  Data: Pointer;
1085begin
1086  if ANode=nil then exit;
1087  LeftMost:=ANode;
1088  repeat
1089    PreNode:=FindPrecessor(LeftMost);
1090    if (PreNode=nil) or (Compare(ANode,PreNode)<>0) then break;
1091    LeftMost:=PreNode;
1092  until false;
1093  if LeftMost=ANode then exit;
1094  Data:=LeftMost.Data;
1095  LeftMost.Data:=ANode.Data;
1096  ANode.Data:=Data;
1097  ANode:=LeftMost;
1098end;
1099
1100procedure TAVLTree.MoveDataRightMost(var ANode: TAVLTreeNode);
1101var
1102  RightMost, PostNode: TAVLTreeNode;
1103  Data: Pointer;
1104begin
1105  if ANode=nil then exit;
1106  RightMost:=ANode;
1107  repeat
1108    PostNode:=FindSuccessor(RightMost);
1109    if (PostNode=nil) or (Compare(ANode,PostNode)<>0) then break;
1110    RightMost:=PostNode;
1111  until false;
1112  if RightMost=ANode then exit;
1113  Data:=RightMost.Data;
1114  RightMost.Data:=ANode.Data;
1115  ANode.Data:=Data;
1116  ANode:=RightMost;
1117end;
1118
1119procedure TAVLTree.ConsistencyCheck;
1120
1121  procedure E(Msg: string);
1122  begin
1123    raise Exception.Create('TAVLTree.ConsistencyCheck: '+Msg);
1124  end;
1125
1126var
1127  RealCount: SizeInt;
1128begin
1129  RealCount:=0;
1130  if FRoot<>nil then begin
1131    FRoot.ConsistencyCheck(Self);
1132    RealCount:=FRoot.GetCount;
1133  end;
1134  if Count<>RealCount then
1135    E('Count<>RealCount');
1136end;
1137
1138procedure TAVLTree.FreeAndClear;
1139
1140  procedure FreeNodeData(ANode: TAVLTreeNode);
1141  begin
1142    if ANode=nil then exit;
1143    FreeNodeData(ANode.Left);
1144    FreeNodeData(ANode.Right);
1145    if ANode.Data<>nil then TObject(ANode.Data).Free;
1146    ANode.Data:=nil;
1147  end;
1148
1149// TAVLTree.FreeAndClear
1150begin
1151  // free all data
1152  FreeNodeData(Root);
1153  // free all nodes
1154  Clear;
1155end;
1156
1157procedure TAVLTree.FreeAndDelete(ANode: TAVLTreeNode);
1158var OldData: TObject;
1159begin
1160  OldData:=TObject(ANode.Data);
1161  Delete(ANode);
1162  OldData.Free;
1163end;
1164
1165function TAVLTree.Equals(Obj: TObject): boolean;
1166begin
1167  if Obj is TAVLTree then
1168    Result:=IsEqual(TAVLTree(Obj),false)
1169  else
1170    Result:=inherited Equals(Obj);
1171end;
1172
1173function TAVLTree.IsEqual(aTree: TAVLTree; CheckDataPointer: boolean): boolean;
1174var
1175  MyNode, OtherNode: TAVLTreeNode;
1176begin
1177  if aTree=Self then exit(true);
1178  Result:=false;
1179  if aTree=nil then exit;
1180  if Count<>aTree.Count then exit;
1181  if OnCompare<>aTree.OnCompare then exit;
1182  if OnObjectCompare<>aTree.OnObjectCompare then exit;
1183  if NodeClass<>aTree.NodeClass then exit;
1184  MyNode:=FindLowest;
1185  OtherNode:=aTree.FindLowest;
1186  while MyNode<>nil do begin
1187    if OtherNode=nil then exit;
1188    if CheckDataPointer then begin
1189      if MyNode.Data<>OtherNode.Data then exit;
1190    end else begin
1191      if Compare(MyNode.Data,OtherNode.Data)<>0 then exit;
1192    end;
1193    MyNode:=MyNode.Successor;
1194    OtherNode:=OtherNode.Successor;
1195  end;
1196  if OtherNode<>nil then exit;
1197  Result:=true;
1198end;
1199
1200procedure TAVLTree.Assign(aTree: TAVLTree);
1201
1202  procedure AssignNode(var MyNode: TAVLTreeNode; OtherNode: TAVLTreeNode);
1203  begin
1204    MyNode:=NewNode;
1205    MyNode.Data:=OtherNode.Data;
1206    MyNode.Balance:=OtherNode.Balance;
1207    if OtherNode.Left<>nil then begin
1208      AssignNode(MyNode.Left,OtherNode.Left);
1209      MyNode.Left.Parent:=MyNode;
1210    end;
1211    if OtherNode.Right<>nil then begin
1212      AssignNode(MyNode.Right,OtherNode.Right);
1213      MyNode.Right.Parent:=MyNode;
1214    end;
1215  end;
1216
1217begin
1218  if aTree=nil then
1219    raise Exception.Create('TAVLTree.Assign aTree=nil');
1220  if IsEqual(aTree,true) then exit;
1221  Clear;
1222  SetCompares(aTree.OnCompare,aTree.OnObjectCompare);
1223  NodeClass:=aTree.NodeClass;
1224  if aTree.Root<>nil then
1225    AssignNode(fRoot,aTree.Root);
1226  FCount:=aTree.Count;
1227end;
1228
1229function TAVLTree.Compare(Data1, Data2: Pointer): integer;
1230begin
1231  if Assigned(FOnCompare) then
1232    Result:=FOnCompare(Data1,Data2)
1233  else
1234    Result:=FOnObjectCompare(Self,Data1,Data2);
1235end;
1236
1237procedure TAVLTree.WriteReportToStream(s: TStream);
1238
1239  procedure WriteStr(const Txt: string);
1240  begin
1241    if Txt='' then exit;
1242    s.Write(Txt[1],length(Txt));
1243  end;
1244
1245  procedure WriteTreeNode(ANode: TAVLTreeNode);
1246  var
1247    b: String;
1248    IsLeft: boolean;
1249    AParent: TAVLTreeNode;
1250    WasLeft: Boolean;
1251  begin
1252    if ANode=nil then exit;
1253    WriteTreeNode(ANode.Right);
1254    AParent:=ANode;
1255    WasLeft:=false;
1256    b:='';
1257    while AParent<>nil do begin
1258      if AParent.Parent=nil then begin
1259        if AParent=ANode then
1260          b:='--'+b
1261        else
1262          b:='  '+b;
1263        break;
1264      end;
1265      IsLeft:=AParent.Parent.Left=AParent;
1266      if AParent=ANode then begin
1267        if IsLeft then
1268          b:='\-'
1269        else
1270          b:='/-';
1271      end else begin
1272        if WasLeft=IsLeft then
1273          b:='  '+b
1274        else
1275          b:='| '+b;
1276      end;
1277      WasLeft:=IsLeft;
1278      AParent:=AParent.Parent;
1279    end;
1280    b:=b+NodeToReportStr(ANode)+LineEnding;
1281    WriteStr(b);
1282    WriteTreeNode(ANode.Left);
1283  end;
1284
1285// TAVLTree.WriteReportToStream
1286begin
1287  WriteStr('-Start-of-AVL-Tree-------------------'+LineEnding);
1288  WriteTreeNode(fRoot);
1289  WriteStr('-End-Of-AVL-Tree---------------------'+LineEnding);
1290end;
1291
1292function TAVLTree.NodeToReportStr(aNode: TAVLTreeNode): string;
1293begin
1294  Result:=Format('%p      Self=%p  Parent=%p  Balance=%d',
1295             [aNode.Data, Pointer(aNode),Pointer(aNode.Parent), aNode.Balance]);
1296end;
1297
1298function TAVLTree.ReportAsString: string;
1299var ms: TMemoryStream;
1300begin
1301  Result:='';
1302  ms:=TMemoryStream.Create;
1303  try
1304    WriteReportToStream(ms);
1305    ms.Position:=0;
1306    SetLength(Result,ms.Size);
1307    if Result<>'' then
1308      ms.Read(Result[1],length(Result));
1309  finally
1310    ms.Free;
1311  end;
1312end;
1313
1314procedure TAVLTree.SetOnCompare(const AValue: TListSortCompare);
1315begin
1316  if AValue=nil then
1317    SetCompares(nil,FOnObjectCompare)
1318  else
1319    SetCompares(AValue,nil);
1320end;
1321
1322procedure TAVLTree.SetNodeManager(NewMgr: TBaseAVLTreeNodeManager;
1323  AutoFree: boolean);
1324// only allowed just after create.
1325begin
1326  if fNodeMgr=NewMgr then exit;
1327  if Count>0 then
1328    raise Exception.Create('TAVLTree.SetNodeManager');
1329  if fNodeMgrAutoFree then
1330    FreeAndNil(fNodeMgr);
1331  fNodeMgr:=NewMgr;
1332  fNodeMgrAutoFree:=AutoFree;
1333end;
1334
1335{ TAVLTreeNode }
1336
1337function TAVLTreeNode.TreeDepth: integer;
1338// longest WAY down. e.g. only one node => 0 !
1339var LeftDepth, RightDepth: integer;
1340begin
1341  if Left<>nil then
1342    LeftDepth:=Left.TreeDepth+1
1343  else
1344    LeftDepth:=0;
1345  if Right<>nil then
1346    RightDepth:=Right.TreeDepth+1
1347  else
1348    RightDepth:=0;
1349  if LeftDepth>RightDepth then
1350    Result:=LeftDepth
1351  else
1352    Result:=RightDepth;
1353end;
1354
1355procedure TAVLTreeNode.ConsistencyCheck(Tree: TAVLTree);
1356
1357  procedure E(Msg: string);
1358  begin
1359    raise Exception.Create('TAVLTreeNode.ConsistencyCheck: '+Msg);
1360  end;
1361
1362var
1363  LeftDepth: SizeInt;
1364  RightDepth: SizeInt;
1365begin
1366  // test left child
1367  if Left<>nil then begin
1368    if Left.Parent<>Self then
1369      E('Left.Parent<>Self');
1370    if Tree.Compare(Left.Data,Data)>0 then
1371      E('Compare(Left.Data,Data)>0');
1372    Left.ConsistencyCheck(Tree);
1373  end;
1374  // test right child
1375  if Right<>nil then begin
1376    if Right.Parent<>Self then
1377      E('Right.Parent<>Self');
1378    if Tree.Compare(Data,Right.Data)>0 then
1379      E('Compare(Data,Right.Data)>0');
1380    Right.ConsistencyCheck(Tree);
1381  end;
1382  // test balance
1383  if Left<>nil then
1384    LeftDepth:=Left.TreeDepth+1
1385  else
1386    LeftDepth:=0;
1387  if Right<>nil then
1388    RightDepth:=Right.TreeDepth+1
1389  else
1390    RightDepth:=0;
1391  if Balance<>(RightDepth-LeftDepth) then
1392    E('Balance['+IntToStr(Balance)+']<>(RightDepth['+IntToStr(RightDepth)+']-LeftDepth['+IntToStr(LeftDepth)+'])');
1393end;
1394
1395function TAVLTreeNode.GetCount: SizeInt;
1396begin
1397  Result:=1;
1398  if Left<>nil then inc(Result,Left.GetCount);
1399  if Right<>nil then inc(Result,Right.GetCount);
1400end;
1401
1402function TAVLTreeNode.Successor: TAVLTreeNode;
1403begin
1404  Result:=Right;
1405  if Result<>nil then begin
1406    while (Result.Left<>nil) do Result:=Result.Left;
1407  end else begin
1408    Result:=Self;
1409    while (Result.Parent<>nil) and (Result.Parent.Right=Result) do
1410      Result:=Result.Parent;
1411    Result:=Result.Parent;
1412  end;
1413end;
1414
1415function TAVLTreeNode.Precessor: TAVLTreeNode;
1416begin
1417  Result:=Left;
1418  if Result<>nil then begin
1419    while (Result.Right<>nil) do Result:=Result.Right;
1420  end else begin
1421    Result:=Self;
1422    while (Result.Parent<>nil) and (Result.Parent.Left=Result) do
1423      Result:=Result.Parent;
1424    Result:=Result.Parent;
1425  end;
1426end;
1427
1428procedure TAVLTreeNode.Clear;
1429begin
1430  Parent:=nil;
1431  Left:=nil;
1432  Right:=nil;
1433  Balance:=0;
1434  Data:=nil;
1435end;
1436
1437
1438
1439{ TAVLTreeNodeMemManager }
1440
1441constructor TAVLTreeNodeMemManager.Create;
1442begin
1443  {$IFDEF CheckAVLTreeNodeManager}
1444  FThreadId:=GetCurrentThreadId;
1445  {$ENDIF}
1446  inherited Create;
1447  FFirstFree:=nil;
1448  FFreeCount:=0;
1449  FCount:=0;
1450  FMinFree:=100;
1451  FMaxFreeRatio:=8; // 1:1
1452end;
1453
1454destructor TAVLTreeNodeMemManager.Destroy;
1455begin
1456  Clear;
1457  inherited Destroy;
1458end;
1459
1460procedure TAVLTreeNodeMemManager.DisposeNode(ANode: TAVLTreeNode);
1461begin
1462  if ANode=nil then exit;
1463  {$IFDEF CheckAVLTreeNodeManager}
1464  if GetCurrentThreadId<>FThreadId then
1465    raise Exception.Create('TAVLTreeNodeMemManager.DisposeNode not thread safe!');
1466  {$ENDIF}
1467  if FCount < 0 then
1468    raise Exception.CreateFmt(
1469      '%s.DisposeNode: FCount (%d) is negative. Should not happen.'
1470     +' FFreeCount=%d, FMinFree=%d, FMaxFreeRatio=%d.',
1471      [ClassName, FCount, FFreeCount, FMinFree, FMaxFreeRatio]);
1472  if (FFreeCount<FMinFree) or (FFreeCount<((FCount shr 3)*FMaxFreeRatio)) then
1473  begin
1474    // add ANode to Free list
1475    ANode.Clear;
1476    ANode.Right:=FFirstFree;
1477    FFirstFree:=ANode;
1478    inc(FFreeCount);
1479    if (FFreeCount>(((8+FMaxFreeRatio)*FCount) shr 3)) then begin
1480      DisposeFirstFreeNode;
1481      DisposeFirstFreeNode;
1482    end;
1483  end else begin
1484    // free list full -> free the ANode
1485    ANode.Free;
1486  end;
1487  dec(FCount);
1488end;
1489
1490function TAVLTreeNodeMemManager.NewNode: TAVLTreeNode;
1491begin
1492  {$IFDEF CheckAVLTreeNodeManager}
1493  if GetCurrentThreadId<>FThreadId then
1494    raise Exception.Create('TAVLTreeNodeMemManager.NewNode: not thread safe!');
1495  {$ENDIF}
1496  if FFirstFree<>nil then begin
1497    // take from free list
1498    Result:=FFirstFree;
1499    FFirstFree:=FFirstFree.Right;
1500    Result.Right:=nil;
1501    dec(FFreeCount);
1502  end else begin
1503    // free list empty -> create new node
1504    Result:=TAVLTreeNode.Create;
1505  end;
1506  inc(FCount);
1507end;
1508
1509procedure TAVLTreeNodeMemManager.Clear;
1510var ANode: TAVLTreeNode;
1511begin
1512  {$IFDEF CheckAVLTreeNodeManager}
1513  if GetCurrentThreadId<>FThreadId then
1514    raise Exception.Create('TAVLTreeNodeMemManager.Clear: not thread safe!');
1515  {$ENDIF}
1516  while FFirstFree<>nil do begin
1517    ANode:=FFirstFree;
1518    FFirstFree:=FFirstFree.Right;
1519    ANode.Right:=nil;
1520    ANode.Free;
1521  end;
1522  FFreeCount:=0;
1523end;
1524
1525procedure TAVLTreeNodeMemManager.SetMaxFreeRatio(NewValue: SizeInt);
1526begin
1527  if NewValue<0 then NewValue:=0;
1528  if NewValue=FMaxFreeRatio then exit;
1529  FMaxFreeRatio:=NewValue;
1530end;
1531
1532procedure TAVLTreeNodeMemManager.SetMinFree(NewValue: SizeInt);
1533begin
1534  if NewValue<0 then NewValue:=0;
1535  if NewValue=FMinFree then exit;
1536  FMinFree:=NewValue;
1537end;
1538
1539procedure TAVLTreeNodeMemManager.DisposeFirstFreeNode;
1540var OldNode: TAVLTreeNode;
1541begin
1542  if FFirstFree=nil then exit;
1543  OldNode:=FFirstFree;
1544  FFirstFree:=FFirstFree.Right;
1545  dec(FFreeCount);
1546  OldNode.Right:=nil;
1547  OldNode.Free;
1548end;
1549
1550
1551initialization
1552  LazNodeMemManager:=TAVLTreeNodeMemManager.Create;
1553
1554finalization
1555  LazNodeMemManager.Free;
1556  LazNodeMemManager:=nil;
1557end.
1558