2
*****************************************************************************
4
* This file is part of the Lazarus Component Library (LCL) *
6
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
7
* for details about the copyright. *
9
* This program is distributed in the hope that it will be useful, *
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
13
*****************************************************************************
15
Author: Mattias Gaertner
18
The Tree is sorted ascending from left to right. That means Compare gives
19
positive values for comparing right with left.
21
TAvgLvlTree is an Average Level binary Tree. This binary tree is always
22
balanced, so that inserting, deleting and finding a node is performed in
25
Tree is sorted ascending.
34
Classes, SysUtils, FPCAdds;
39
TObjectSortCompare = function(Tree: TAvgLvlTree; Data1, Data2: Pointer
42
TAvgLvlTreeNode = class
44
Parent, Left, Right: TAvgLvlTreeNode;
48
function TreeDepth: integer; // longest WAY down. e.g. only one node => 0 !
50
PAvgLvlTreeNode = ^TAvgLvlTreeNode;
52
TAvgLvlTreeNodeMemManager = class;
59
FNodeMemManager: TAvgLvlTreeNodeMemManager;
60
FOnCompare: TListSortCompare;
61
FOnObjectCompare: TObjectSortCompare;
62
procedure BalanceAfterInsert(ANode: TAvgLvlTreeNode);
63
procedure BalanceAfterDelete(ANode: TAvgLvlTreeNode);
64
function FindInsertPos(Data: Pointer): TAvgLvlTreeNode;
65
procedure SetOnCompare(const AValue: TListSortCompare);
66
procedure SetOnObjectCompare(const AValue: TObjectSortCompare);
67
procedure SetCompares(const NewCompare: TListSortCompare;
68
const NewObjectCompare: TObjectSortCompare);
70
Root: TAvgLvlTreeNode;
71
function Compare(Data1, Data2: Pointer): integer;
72
function Find(Data: Pointer): TAvgLvlTreeNode;
73
function FindKey(Key: Pointer;
74
OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode;
75
function FindNearestKey(Key: Pointer;
76
OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode;
77
function FindSuccessor(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode;
78
function FindPrecessor(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode;
79
function FindLowest: TAvgLvlTreeNode;
80
function FindHighest: TAvgLvlTreeNode;
81
function FindNearest(Data: Pointer): TAvgLvlTreeNode;
82
function FindPointer(Data: Pointer): TAvgLvlTreeNode;
83
function FindLeftMost(Data: Pointer): TAvgLvlTreeNode;
84
function FindRightMost(Data: Pointer): TAvgLvlTreeNode;
85
function FindLeftMostKey(Key: Pointer;
86
OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode;
87
function FindRightMostKey(Key: Pointer;
88
OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode;
89
function FindLeftMostSameKey(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode;
90
function FindRightMostSameKey(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode;
91
procedure Add(ANode: TAvgLvlTreeNode);
92
function Add(Data: Pointer): TAvgLvlTreeNode;
93
procedure Delete(ANode: TAvgLvlTreeNode);
94
procedure Remove(Data: Pointer);
95
procedure RemovePointer(Data: Pointer);
96
procedure MoveDataLeftMost(var ANode: TAvgLvlTreeNode);
97
procedure MoveDataRightMost(var ANode: TAvgLvlTreeNode);
98
property OnCompare: TListSortCompare read FOnCompare write SetOnCompare;
99
property OnObjectCompare: TObjectSortCompare read FOnObjectCompare write SetOnObjectCompare;
101
procedure FreeAndClear;
102
procedure FreeAndDelete(ANode: TAvgLvlTreeNode);
103
property Count: integer read FCount;
104
function ConsistencyCheck: integer;
105
procedure WriteReportToStream(s: TStream; var StreamSize: TStreamSeekType);
106
function ReportAsString: string;
107
property NodeMemManager: TAvgLvlTreeNodeMemManager read FNodeMemManager write FNodeMemManager;
108
constructor Create(OnCompareMethod: TListSortCompare);
109
constructor CreateObjectCompare(OnCompareMethod: TObjectSortCompare);
111
destructor Destroy; override;
113
PAvgLvlTree = ^TAvgLvlTree;
115
TAvgLvlTreeNodeMemManager = class
117
FFirstFree: TAvgLvlTreeNode;
121
FMaxFreeRatio: integer;
122
procedure SetMaxFreeRatio(NewValue: integer);
123
procedure SetMinFree(NewValue: integer);
124
procedure DisposeFirstFreeNode;
126
procedure DisposeNode(ANode: TAvgLvlTreeNode);
127
function NewNode: TAvgLvlTreeNode;
128
property MinimumFreeNode: integer read FMinFree write SetMinFree;
129
property MaximumFreeNodeRatio: integer
130
read FMaxFreeRatio write SetMaxFreeRatio; // in one eighth steps
131
property Count: integer read FCount;
134
destructor Destroy; override;
139
{ TPointerToPointerTree - Associative array }
141
TPointerToPointerItem = record
145
PPointerToPointerItem = ^TPointerToPointerItem;
147
TPointerToPointerTree = class
150
function GetCount: Integer;
151
function GetValues(const Key: Pointer): Pointer;
152
procedure SetValues(const Key: Pointer; const AValue: Pointer);
153
function FindNode(const Key: Pointer): TAvgLvlTreeNode;
154
function GetNode(Node: TAvgLvlTreeNode; out Key, Value: Pointer): Boolean;
157
destructor Destroy; override;
159
procedure Remove(Key: Pointer);
160
function Contains(const Key: Pointer): Boolean;
161
function GetFirst(out Key, Value: Pointer): Boolean;
162
function GetLast(out Key, Value: Pointer): Boolean;
163
function GetNext(const Key: Pointer; out NextKey, NextValue: Pointer): Boolean;
164
function GetPrev(const Key: Pointer; out PrevKey, PrevValue: Pointer): Boolean;
165
property Count: Integer read GetCount;
166
property Values[const Key: Pointer]: Pointer read GetValues write SetValues; default;
167
property Tree: TAvgLvlTree read FItems;
171
function ComparePointerToPointerItems(Data1, Data2: Pointer): integer;
172
function ComparePointerWithPtrToPtrItem(Key, Data: Pointer): Integer;
176
{ TStringToStringTree - Associative array }
178
TStringToStringItem = record
182
PStringToStringItem = ^TStringToStringItem;
184
TStringToStringTree = class
186
FCompareItems: TListSortCompare;
187
FCompareNameWithItem: TListSortCompare;
189
function GetCount: Integer;
190
function GetValues(const Name: string): string;
191
procedure SetValues(const Name: string; const AValue: string);
192
function FindNode(const Name: string): TAvgLvlTreeNode;
193
function GetNode(Node: TAvgLvlTreeNode; out Name, Value: string): Boolean;
195
constructor Create(CaseSensitive: boolean);
196
constructor Create(const ACompareItems, ACompareNameWithItem: TListSortCompare);
197
destructor Destroy; override;
199
procedure Assign(Src: TStringToStringTree);
200
function Contains(const Name: string): Boolean;
201
procedure Delete(const Name: string);
202
procedure Add(const Name, Value, Delimiter: string);
203
procedure AddNameValues(List: TStrings);
204
procedure AddValues(List: TStrings);
205
function GetFirst(out Name, Value: string): Boolean;
206
function GetLast(out Name, Value: string): Boolean;
207
function GetNext(const Name: string; out NextName, NextValue: string): Boolean;
208
function GetPrev(const Name: string; out PrevName, PrevValue: string): Boolean;
209
property Count: Integer read GetCount;
210
property Values[const Name: string]: string read GetValues write SetValues; default;
211
property Tree: TAvgLvlTree read FItems;
212
property CompareItems: TListSortCompare read FCompareItems;
213
property CompareNameWithItem: TListSortCompare read FCompareNameWithItem;
216
function CompareStringToStringItems(Data1, Data2: Pointer): integer;
217
function ComparePAnsiStringWithStrToStrItem(Key, Data: Pointer): Integer;
218
function CompareStringToStringItemsI(Data1, Data2: Pointer): integer;
219
function ComparePAnsiStringWithStrToStrItemI(Key, Data: Pointer): Integer;
225
function ComparePointer(Data1, Data2: Pointer): integer;
227
if Data1>Data2 then Result:=-1
228
else if Data1<Data2 then Result:=1
232
function ComparePointerToPointerItems(Data1, Data2: Pointer): integer;
234
Result:=ComparePointer(PPointerToPointerItem(Data1)^.Key,
235
PPointerToPointerItem(Data2)^.Key);
238
function ComparePointerWithPtrToPtrItem(Key, Data: Pointer): Integer;
240
Result:=ComparePointer(Key,PPointerToPointerItem(Data)^.Key);
243
function CompareStringToStringItems(Data1, Data2: Pointer): integer;
245
Result:=CompareStr(PStringToStringItem(Data1)^.Name,
246
PStringToStringItem(Data2)^.Name);
249
function CompareStringToStringItemsI(Data1, Data2: Pointer): integer;
251
Result:=CompareText(PStringToStringItem(Data1)^.Name,
252
PStringToStringItem(Data2)^.Name);
255
function ComparePAnsiStringWithStrToStrItem(Key, Data: Pointer): Integer;
257
Result:=CompareStr(PAnsiString(Key)^,PStringToStringItem(Data)^.Name);
260
function ComparePAnsiStringWithStrToStrItemI(Key, Data: Pointer): Integer;
262
Result:=CompareText(PAnsiString(Key)^,PStringToStringItem(Data)^.Name);
268
function TAvgLvlTree.Add(Data: Pointer): TAvgLvlTreeNode;
270
if NodeMemManager<>nil then
271
Result:=NodeMemManager.NewNode
273
Result:=TAvgLvlTreeNode.Create;
278
procedure TAvgLvlTree.Add(ANode: TAvgLvlTreeNode);
279
// add a node. If there are already nodes with the same value it will be
280
// inserted rightmost
281
var InsertPos: TAvgLvlTreeNode;
287
if Root<>nil then begin
288
InsertPos:=FindInsertPos(ANode.Data);
289
InsertComp:=Compare(ANode.Data,InsertPos.Data);
290
ANode.Parent:=InsertPos;
291
if InsertComp<0 then begin
292
// insert to the left
293
InsertPos.Left:=ANode;
295
// insert to the right
296
InsertPos.Right:=ANode;
298
BalanceAfterInsert(ANode);
305
function TAvgLvlTree.FindLowest: TAvgLvlTreeNode;
309
while Result.Left<>nil do Result:=Result.Left;
312
function TAvgLvlTree.FindHighest: TAvgLvlTreeNode;
316
while Result.Right<>nil do Result:=Result.Right;
319
procedure TAvgLvlTree.BalanceAfterDelete(ANode: TAvgLvlTreeNode);
320
var OldParent, OldRight, OldRightLeft, OldLeft, OldLeftRight,
321
OldRightLeftLeft, OldRightLeftRight, OldLeftRightLeft, OldLeftRightRight
324
if (ANode=nil) then exit;
325
if ((ANode.Balance=+1) or (ANode.Balance=-1)) then exit;
326
OldParent:=ANode.Parent;
327
if (ANode.Balance=0) then begin
328
// Treeheight has decreased by one
329
if (OldParent<>nil) then begin
330
if(OldParent.Left=ANode) then
331
Inc(OldParent.Balance)
333
Dec(OldParent.Balance);
334
BalanceAfterDelete(OldParent);
338
if (ANode.Balance=+2) then begin
339
// Node is overweighted to the right
340
OldRight:=ANode.Right;
341
if (OldRight.Balance>=0) then begin
342
// OldRight.Balance=={0 or -1}
344
OldRightLeft:=OldRight.Left;
345
if (OldParent<>nil) then begin
346
if (OldParent.Left=ANode) then
347
OldParent.Left:=OldRight
349
OldParent.Right:=OldRight;
352
ANode.Parent:=OldRight;
353
ANode.Right:=OldRightLeft;
354
OldRight.Parent:=OldParent;
355
OldRight.Left:=ANode;
356
if (OldRightLeft<>nil) then
357
OldRightLeft.Parent:=ANode;
358
ANode.Balance:=(1-OldRight.Balance);
359
Dec(OldRight.Balance);
360
BalanceAfterDelete(OldRight);
362
// OldRight.Balance=-1
363
// double rotate right left
364
OldRightLeft:=OldRight.Left;
365
OldRightLeftLeft:=OldRightLeft.Left;
366
OldRightLeftRight:=OldRightLeft.Right;
367
if (OldParent<>nil) then begin
368
if (OldParent.Left=ANode) then
369
OldParent.Left:=OldRightLeft
371
OldParent.Right:=OldRightLeft;
374
ANode.Parent:=OldRightLeft;
375
ANode.Right:=OldRightLeftLeft;
376
OldRight.Parent:=OldRightLeft;
377
OldRight.Left:=OldRightLeftRight;
378
OldRightLeft.Parent:=OldParent;
379
OldRightLeft.Left:=ANode;
380
OldRightLeft.Right:=OldRight;
381
if (OldRightLeftLeft<>nil) then
382
OldRightLeftLeft.Parent:=ANode;
383
if (OldRightLeftRight<>nil) then
384
OldRightLeftRight.Parent:=OldRight;
385
if (OldRightLeft.Balance<=0) then
389
if (OldRightLeft.Balance>=0) then
392
OldRight.Balance:=+1;
393
OldRightLeft.Balance:=0;
394
BalanceAfterDelete(OldRightLeft);
398
// Node is overweighted to the left
400
if (OldLeft.Balance<=0) then begin
402
OldLeftRight:=OldLeft.Right;
403
if (OldParent<>nil) then begin
404
if (OldParent.Left=ANode) then
405
OldParent.Left:=OldLeft
407
OldParent.Right:=OldLeft;
410
ANode.Parent:=OldLeft;
411
ANode.Left:=OldLeftRight;
412
OldLeft.Parent:=OldParent;
413
OldLeft.Right:=ANode;
414
if (OldLeftRight<>nil) then
415
OldLeftRight.Parent:=ANode;
416
ANode.Balance:=(-1-OldLeft.Balance);
417
Inc(OldLeft.Balance);
418
BalanceAfterDelete(OldLeft);
420
// OldLeft.Balance = 1
421
// double rotate left right
422
OldLeftRight:=OldLeft.Right;
423
OldLeftRightLeft:=OldLeftRight.Left;
424
OldLeftRightRight:=OldLeftRight.Right;
425
if (OldParent<>nil) then begin
426
if (OldParent.Left=ANode) then
427
OldParent.Left:=OldLeftRight
429
OldParent.Right:=OldLeftRight;
432
ANode.Parent:=OldLeftRight;
433
ANode.Left:=OldLeftRightRight;
434
OldLeft.Parent:=OldLeftRight;
435
OldLeft.Right:=OldLeftRightLeft;
436
OldLeftRight.Parent:=OldParent;
437
OldLeftRight.Left:=OldLeft;
438
OldLeftRight.Right:=ANode;
439
if (OldLeftRightLeft<>nil) then
440
OldLeftRightLeft.Parent:=OldLeft;
441
if (OldLeftRightRight<>nil) then
442
OldLeftRightRight.Parent:=ANode;
443
if (OldLeftRight.Balance>=0) then
447
if (OldLeftRight.Balance<=0) then
451
OldLeftRight.Balance:=0;
452
BalanceAfterDelete(OldLeftRight);
457
procedure TAvgLvlTree.BalanceAfterInsert(ANode: TAvgLvlTreeNode);
458
var OldParent, OldParentParent, OldRight, OldRightLeft, OldRightRight, OldLeft,
459
OldLeftLeft, OldLeftRight: TAvgLvlTreeNode;
461
OldParent:=ANode.Parent;
462
if (OldParent=nil) then exit;
463
if (OldParent.Left=ANode) then begin
465
dec(OldParent.Balance);
466
if (OldParent.Balance=0) then exit;
467
if (OldParent.Balance=-1) then begin
468
BalanceAfterInsert(OldParent);
471
// OldParent.Balance=-2
472
if (ANode.Balance=-1) then begin
474
OldRight:=ANode.Right;
475
OldParentParent:=OldParent.Parent;
476
if (OldParentParent<>nil) then begin
477
// OldParent has GrandParent. GrandParent gets new child
478
if (OldParentParent.Left=OldParent) then
479
OldParentParent.Left:=ANode
481
OldParentParent.Right:=ANode;
483
// OldParent was root node. New root node
486
ANode.Parent:=OldParentParent;
487
ANode.Right:=OldParent;
488
OldParent.Parent:=ANode;
489
OldParent.Left:=OldRight;
490
if (OldRight<>nil) then
491
OldRight.Parent:=OldParent;
493
OldParent.Balance:=0;
497
OldParentParent:=OldParent.Parent;
498
OldRight:=ANode.Right;
499
OldRightLeft:=OldRight.Left;
500
OldRightRight:=OldRight.Right;
501
if (OldParentParent<>nil) then begin
502
// OldParent has GrandParent. GrandParent gets new child
503
if (OldParentParent.Left=OldParent) then
504
OldParentParent.Left:=OldRight
506
OldParentParent.Right:=OldRight;
508
// OldParent was root node. new root node
511
OldRight.Parent:=OldParentParent;
512
OldRight.Left:=ANode;
513
OldRight.Right:=OldParent;
514
ANode.Parent:=OldRight;
515
ANode.Right:=OldRightLeft;
516
OldParent.Parent:=OldRight;
517
OldParent.Left:=OldRightRight;
518
if (OldRightLeft<>nil) then
519
OldRightLeft.Parent:=ANode;
520
if (OldRightRight<>nil) then
521
OldRightRight.Parent:=OldParent;
522
if (OldRight.Balance<=0) then
526
if (OldRight.Balance=-1) then
529
OldParent.Balance:=0;
534
Inc(OldParent.Balance);
535
if (OldParent.Balance=0) then exit;
536
if (OldParent.Balance=+1) then begin
537
BalanceAfterInsert(OldParent);
540
// OldParent.Balance = +2
541
if(ANode.Balance=+1) then begin
544
OldParentParent:=OldParent.Parent;
545
if (OldParentParent<>nil) then begin
546
// Parent has GrandParent . GrandParent gets new child
547
if(OldParentParent.Left=OldParent) then
548
OldParentParent.Left:=ANode
550
OldParentParent.Right:=ANode;
552
// OldParent was root node . new root node
555
ANode.Parent:=OldParentParent;
556
ANode.Left:=OldParent;
557
OldParent.Parent:=ANode;
558
OldParent.Right:=OldLeft;
559
if (OldLeft<>nil) then
560
OldLeft.Parent:=OldParent;
562
OldParent.Balance:=0;
567
OldParentParent:=OldParent.Parent;
568
OldLeftLeft:=OldLeft.Left;
569
OldLeftRight:=OldLeft.Right;
570
if (OldParentParent<>nil) then begin
571
// OldParent has GrandParent . GrandParent gets new child
572
if (OldParentParent.Left=OldParent) then
573
OldParentParent.Left:=OldLeft
575
OldParentParent.Right:=OldLeft;
577
// OldParent was root node . new root node
580
OldLeft.Parent:=OldParentParent;
581
OldLeft.Left:=OldParent;
582
OldLeft.Right:=ANode;
583
ANode.Parent:=OldLeft;
584
ANode.Left:=OldLeftRight;
585
OldParent.Parent:=OldLeft;
586
OldParent.Right:=OldLeftLeft;
587
if (OldLeftLeft<>nil) then
588
OldLeftLeft.Parent:=OldParent;
589
if (OldLeftRight<>nil) then
590
OldLeftRight.Parent:=ANode;
591
if (OldLeft.Balance>=0) then
595
if (OldLeft.Balance=+1) then
596
OldParent.Balance:=-1
598
OldParent.Balance:=0;
604
procedure TAvgLvlTree.Clear;
606
procedure DeleteNode(ANode: TAvgLvlTreeNode);
608
if ANode<>nil then begin
609
if ANode.Left<>nil then DeleteNode(ANode.Left);
610
if ANode.Right<>nil then DeleteNode(ANode.Right);
612
if NodeMemManager<>nil then
613
NodeMemManager.DisposeNode(ANode)
625
constructor TAvgLvlTree.Create(OnCompareMethod: TListSortCompare);
628
FOnCompare:=OnCompareMethod;
631
constructor TAvgLvlTree.CreateObjectCompare(
632
OnCompareMethod: TObjectSortCompare);
635
FOnObjectCompare:=OnCompareMethod;
638
constructor TAvgLvlTree.Create;
640
Create(@ComparePointer);
643
procedure TAvgLvlTree.Delete(ANode: TAvgLvlTreeNode);
644
var OldParent, OldLeft, OldRight, Successor, OldSuccParent, OldSuccLeft,
645
OldSuccRight: TAvgLvlTreeNode;
648
OldParent:=ANode.Parent;
649
OldBalance:=ANode.Balance;
652
if ((ANode.Left=nil) and (ANode.Right=nil)) then begin
653
// Node is Leaf (no children)
654
if (OldParent<>nil) then begin
656
if (OldParent.Left=ANode) then begin
657
// Node is left Son of OldParent
659
Inc(OldParent.Balance);
661
// Node is right Son of OldParent
662
OldParent.Right:=nil;
663
Dec(OldParent.Balance);
665
BalanceAfterDelete(OldParent);
667
// Node is the only node of tree
671
if NodeMemManager<>nil then
672
NodeMemManager.DisposeNode(ANode)
677
if (ANode.Right=nil) then begin
679
// and because DelNode is AVL, Right has no childrens
680
// replace DelNode with Left
683
OldLeft.Parent:=OldParent;
684
if (OldParent<>nil) then begin
685
if (OldParent.Left=ANode) then begin
686
OldParent.Left:=OldLeft;
687
Inc(OldParent.Balance);
689
OldParent.Right:=OldLeft;
690
Dec(OldParent.Balance);
692
BalanceAfterDelete(OldParent);
697
if NodeMemManager<>nil then
698
NodeMemManager.DisposeNode(ANode)
703
if (ANode.Left=nil) then begin
705
// and because DelNode is AVL, Left has no childrens
706
// replace DelNode with Right
707
OldRight:=ANode.Right;
709
OldRight.Parent:=OldParent;
710
if (OldParent<>nil) then begin
711
if (OldParent.Left=ANode) then begin
712
OldParent.Left:=OldRight;
713
Inc(OldParent.Balance);
715
OldParent.Right:=OldRight;
716
Dec(OldParent.Balance);
718
BalanceAfterDelete(OldParent);
723
if NodeMemManager<>nil then
724
NodeMemManager.DisposeNode(ANode)
729
// DelNode has both: Left and Right
730
// Replace ANode with symmetric Successor
731
Successor:=FindSuccessor(ANode);
733
OldRight:=ANode.Right;
734
OldSuccParent:=Successor.Parent;
735
OldSuccLeft:=Successor.Left;
736
OldSuccRight:=Successor.Right;
737
ANode.Balance:=Successor.Balance;
738
Successor.Balance:=OldBalance;
739
if (OldSuccParent<>ANode) then begin
740
// at least one node between ANode and Successor
741
ANode.Parent:=Successor.Parent;
742
if (OldSuccParent.Left=Successor) then
743
OldSuccParent.Left:=ANode
745
OldSuccParent.Right:=ANode;
746
Successor.Right:=OldRight;
747
OldRight.Parent:=Successor;
749
// Successor is right son of ANode
750
ANode.Parent:=Successor;
751
Successor.Right:=ANode;
753
Successor.Left:=OldLeft;
755
OldLeft.Parent:=Successor;
756
Successor.Parent:=OldParent;
757
ANode.Left:=OldSuccLeft;
758
if ANode.Left<>nil then
759
ANode.Left.Parent:=ANode;
760
ANode.Right:=OldSuccRight;
761
if ANode.Right<>nil then
762
ANode.Right.Parent:=ANode;
763
if (OldParent<>nil) then begin
764
if (OldParent.Left=ANode) then
765
OldParent.Left:=Successor
767
OldParent.Right:=Successor;
770
// delete Node as usual
774
procedure TAvgLvlTree.Remove(Data: Pointer);
775
var ANode: TAvgLvlTreeNode;
782
procedure TAvgLvlTree.RemovePointer(Data: Pointer);
784
ANode: TAvgLvlTreeNode;
786
ANode:=FindPointer(Data);
791
destructor TAvgLvlTree.Destroy;
797
function TAvgLvlTree.Find(Data: Pointer): TAvgLvlTreeNode;
801
while (Result<>nil) do begin
802
Comp:=Compare(Data,Result.Data);
812
function TAvgLvlTree.FindKey(Key: Pointer;
813
OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode;
817
while (Result<>nil) do begin
818
Comp:=OnCompareKeyWithData(Key,Result.Data);
828
function TAvgLvlTree.FindNearestKey(Key: Pointer;
829
OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode;
833
while (Result<>nil) do begin
834
Comp:=OnCompareKeyWithData(Key,Result.Data);
837
if Result.Left<>nil then
842
if Result.Right<>nil then
850
function TAvgLvlTree.FindLeftMostKey(Key: Pointer;
851
OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode;
853
Result:=FindLeftMostSameKey(FindKey(Key,OnCompareKeyWithData));
856
function TAvgLvlTree.FindRightMostKey(Key: Pointer;
857
OnCompareKeyWithData: TListSortCompare): TAvgLvlTreeNode;
859
Result:=FindRightMostSameKey(FindKey(Key,OnCompareKeyWithData));
862
function TAvgLvlTree.FindLeftMostSameKey(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode;
864
LeftNode: TAvgLvlTreeNode;
867
if ANode<>nil then begin
871
LeftNode:=FindPrecessor(Result);
872
if (LeftNode=nil) or (Compare(Data,LeftNode.Data)<>0) then break;
880
function TAvgLvlTree.FindRightMostSameKey(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode;
882
RightNode: TAvgLvlTreeNode;
885
if ANode<>nil then begin
889
RightNode:=FindSuccessor(Result);
890
if (RightNode=nil) or (Compare(Data,RightNode.Data)<>0) then break;
898
function TAvgLvlTree.FindNearest(Data: Pointer): TAvgLvlTreeNode;
902
while (Result<>nil) do begin
903
Comp:=Compare(Data,Result.Data);
906
if Result.Left<>nil then
911
if Result.Right<>nil then
919
function TAvgLvlTree.FindPointer(Data: Pointer): TAvgLvlTreeNode;
920
// same as Find, but not comparing for key, but same Data too
922
Result:=FindLeftMost(Data);
923
while (Result<>nil) do begin
924
if Result.Data=Data then break;
925
Result:=FindSuccessor(Result);
926
if Compare(Data,Result.Data)<>0 then Result:=nil;
930
function TAvgLvlTree.FindLeftMost(Data: Pointer): TAvgLvlTreeNode;
932
Left: TAvgLvlTreeNode;
935
while (Result<>nil) do begin
936
Left:=FindPrecessor(Result);
937
if (Left=nil) or (Compare(Data,Left.Data)<>0) then break;
942
function TAvgLvlTree.FindRightMost(Data: Pointer): TAvgLvlTreeNode;
944
Right: TAvgLvlTreeNode;
947
while (Result<>nil) do begin
948
Right:=FindSuccessor(Result);
949
if (Right=nil) or (Compare(Data,Right.Data)<>0) then break;
954
function TAvgLvlTree.FindInsertPos(Data: Pointer): TAvgLvlTreeNode;
958
while (Result<>nil) do begin
959
Comp:=Compare(Data,Result.Data);
961
if Result.Left<>nil then
966
if Result.Right<>nil then
974
function TAvgLvlTree.FindSuccessor(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode;
977
if Result<>nil then begin
978
while (Result.Left<>nil) do Result:=Result.Left;
981
while (Result.Parent<>nil) and (Result.Parent.Right=Result) do
982
Result:=Result.Parent;
983
Result:=Result.Parent;
987
function TAvgLvlTree.FindPrecessor(ANode: TAvgLvlTreeNode): TAvgLvlTreeNode;
990
if Result<>nil then begin
991
while (Result.Right<>nil) do Result:=Result.Right;
994
while (Result.Parent<>nil) and (Result.Parent.Left=Result) do
995
Result:=Result.Parent;
996
Result:=Result.Parent;
1000
procedure TAvgLvlTree.MoveDataLeftMost(var ANode: TAvgLvlTreeNode);
1001
var LeftMost, PreNode: TAvgLvlTreeNode;
1004
if ANode=nil then exit;
1007
PreNode:=FindPrecessor(LeftMost);
1008
if (PreNode=nil) or (Compare(ANode,PreNode)<>0) then break;
1011
if LeftMost=ANode then exit;
1012
Data:=LeftMost.Data;
1013
LeftMost.Data:=ANode.Data;
1018
procedure TAvgLvlTree.MoveDataRightMost(var ANode: TAvgLvlTreeNode);
1019
var RightMost, PostNode: TAvgLvlTreeNode;
1022
if ANode=nil then exit;
1025
PostNode:=FindSuccessor(RightMost);
1026
if (PostNode=nil) or (Compare(ANode,PostNode)<>0) then break;
1027
RightMost:=PostNode;
1029
if RightMost=ANode then exit;
1030
Data:=RightMost.Data;
1031
RightMost.Data:=ANode.Data;
1036
function TAvgLvlTree.ConsistencyCheck: integer;
1037
var RealCount: integer;
1039
function CheckNode(ANode: TAvgLvlTreeNode): integer;
1040
var LeftDepth, RightDepth: integer;
1042
if ANode=nil then begin
1048
if ANode.Left<>nil then begin
1049
if ANode.Left.Parent<>ANode then begin
1052
if Compare(ANode.Left.Data,ANode.Data)>0 then begin
1055
Result:=CheckNode(ANode.Left);
1056
if Result<>0 then exit;
1059
if ANode.Right<>nil then begin
1060
if ANode.Right.Parent<>ANode then begin
1063
if Compare(ANode.Data,ANode.Right.Data)>0 then begin
1066
Result:=CheckNode(ANode.Right);
1067
if Result<>0 then exit;
1070
if ANode.Left<>nil then
1071
LeftDepth:=ANode.Left.TreeDepth+1
1074
if ANode.Right<>nil then
1075
RightDepth:=ANode.Right.TreeDepth+1
1078
if ANode.Balance<>(RightDepth-LeftDepth) then begin
1085
// TAvgLvlTree.ConsistencyCheck
1088
Result:=CheckNode(Root);
1089
if Result<>0 then exit;
1090
if FCount<>RealCount then begin
1096
procedure TAvgLvlTree.FreeAndClear;
1098
procedure FreeNode(ANode: TAvgLvlTreeNode);
1100
if ANode=nil then exit;
1101
FreeNode(ANode.Left);
1102
FreeNode(ANode.Right);
1103
if ANode.Data<>nil then TObject(ANode.Data).Free;
1107
// TAvgLvlTree.FreeAndClear
1115
procedure TAvgLvlTree.FreeAndDelete(ANode: TAvgLvlTreeNode);
1116
var OldData: TObject;
1118
OldData:=TObject(ANode.Data);
1123
procedure TAvgLvlTree.WriteReportToStream(s: TStream;
1124
var StreamSize: TStreamSeekType);
1127
procedure WriteStr(const Txt: string);
1130
s.Write(Txt[1],length(Txt));
1131
inc(StreamSize,length(Txt));
1134
procedure WriteTreeNode(ANode: TAvgLvlTreeNode; const Prefix: string);
1137
if ANode=nil then exit;
1138
WriteTreeNode(ANode.Right,Prefix+' ');
1139
b:=Prefix+Format('%p Self=%p Parent=%p Balance=%d#13#10', [
1140
ANode.Data, Pointer(ANode),Pointer(ANode.Parent), ANode.Balance]);
1142
WriteTreeNode(ANode.Left,Prefix+' ');
1145
// TAvgLvlTree.WriteReportToStream
1147
h:='Consistency: '+IntToStr(ConsistencyCheck)+' ---------------------'+#13#10;
1149
WriteTreeNode(Root,' ');
1150
h:='-End-Of-AVL-Tree---------------------'+#13#10;
1154
function TAvgLvlTree.ReportAsString: string;
1155
var ms: TMemoryStream;
1156
StreamSize: TStreamSeekType;
1159
ms:=TMemoryStream.Create;
1162
WriteReportToStream(nil,StreamSize);
1163
ms.Size:=StreamSize;
1164
if StreamSize>0 then begin
1166
WriteReportToStream(ms,StreamSize);
1168
SetLength(Result,StreamSize);
1169
ms.Read(Result[1],TMemStreamSeekType(StreamSize));
1176
procedure TAvgLvlTree.SetOnCompare(const AValue: TListSortCompare);
1179
SetCompares(nil,FOnObjectCompare)
1181
SetCompares(AValue,nil);
1184
procedure TAvgLvlTree.SetOnObjectCompare(const AValue: TObjectSortCompare);
1187
SetCompares(FOnCompare,nil)
1189
SetCompares(nil,AValue);
1192
procedure TAvgLvlTree.SetCompares(const NewCompare: TListSortCompare;
1193
const NewObjectCompare: TObjectSortCompare);
1195
ANode: TAvgLvlTreeNode;
1196
i, OldCount: integer;
1198
if (FOnCompare=NewCompare) and (FOnObjectCompare=NewObjectCompare) then exit;
1199
// sort the tree again
1200
if Count>0 then begin
1202
GetMem(List,SizeOf(Pointer)*OldCount);
1204
// save the data in a list
1207
while ANode<>nil do begin
1208
List[i]:=ANode.Data;
1210
ANode:=FindSuccessor(ANode);
1214
// set the new compare function
1215
FOnCompare:=NewCompare;
1216
FOnObjectCompare:=NewObjectCompare;
1218
for i:=0 to OldCount-1 do
1226
function TAvgLvlTree.Compare(Data1, Data2: Pointer): integer;
1228
if Assigned(FOnCompare) then
1229
Result:=FOnCompare(Data1,Data2)
1231
Result:=FOnObjectCompare(Self,Data1,Data2);
1237
function TAvgLvlTreeNode.TreeDepth: integer;
1238
// longest WAY down. e.g. only one node => 0 !
1239
var LeftDepth, RightDepth: integer;
1242
LeftDepth:=Left.TreeDepth+1
1246
RightDepth:=Right.TreeDepth+1
1249
if LeftDepth>RightDepth then
1255
procedure TAvgLvlTreeNode.Clear;
1264
{ TAvgLvlTreeNodeMemManager }
1266
constructor TAvgLvlTreeNodeMemManager.Create;
1273
FMaxFreeRatio:=8; // 1:1
1276
destructor TAvgLvlTreeNodeMemManager.Destroy;
1282
procedure TAvgLvlTreeNodeMemManager.DisposeNode(ANode: TAvgLvlTreeNode);
1284
if ANode=nil then exit;
1285
if (FFreeCount<FMinFree) or (FFreeCount<((FCount shr 3)*FMaxFreeRatio)) then
1287
// add ANode to Free list
1289
ANode.Right:=FFirstFree;
1292
if (FFreeCount>(((8+FMaxFreeRatio)*FCount) shr 3)) then begin
1293
DisposeFirstFreeNode;
1294
DisposeFirstFreeNode;
1297
// free list full -> free the ANode
1303
function TAvgLvlTreeNodeMemManager.NewNode: TAvgLvlTreeNode;
1305
if FFirstFree<>nil then begin
1306
// take from free list
1308
FFirstFree:=FFirstFree.Right;
1311
// free list empty -> create new node
1312
Result:=TAvgLvlTreeNode.Create;
1317
procedure TAvgLvlTreeNodeMemManager.Clear;
1318
var ANode: TAvgLvlTreeNode;
1320
while FFirstFree<>nil do begin
1322
FFirstFree:=FFirstFree.Right;
1329
procedure TAvgLvlTreeNodeMemManager.SetMaxFreeRatio(NewValue: integer);
1331
if NewValue<0 then NewValue:=0;
1332
if NewValue=FMaxFreeRatio then exit;
1333
FMaxFreeRatio:=NewValue;
1336
procedure TAvgLvlTreeNodeMemManager.SetMinFree(NewValue: integer);
1338
if NewValue<0 then NewValue:=0;
1339
if NewValue=FMinFree then exit;
1343
procedure TAvgLvlTreeNodeMemManager.DisposeFirstFreeNode;
1344
var OldNode: TAvgLvlTreeNode;
1346
if FFirstFree=nil then exit;
1347
OldNode:=FFirstFree;
1348
FFirstFree:=FFirstFree.Right;
1354
{ TStringToStringTree }
1356
function TStringToStringTree.GetCount: Integer;
1358
Result:=FItems.Count;
1361
function TStringToStringTree.GetValues(const Name: string): string;
1363
Node: TAvgLvlTreeNode;
1365
Node:=FindNode(Name);
1367
Result:=PStringToStringItem(Node.Data)^.Value
1372
procedure TStringToStringTree.SetValues(const Name: string; const AValue: string
1375
NewItem: PStringToStringItem;
1376
Node: TAvgLvlTreeNode;
1378
Node:=FindNode(Name);
1380
PStringToStringItem(Node.Data)^.Value:=AValue
1383
NewItem^.Name:=Name;
1384
NewItem^.Value:=AValue;
1385
FItems.Add(NewItem);
1389
function TStringToStringTree.FindNode(const Name: string): TAvgLvlTreeNode;
1391
Result:=FItems.FindKey(@Name,FCompareNameWithItem);
1394
function TStringToStringTree.GetNode(Node: TAvgLvlTreeNode;
1395
out Name, Value: string): Boolean;
1397
Item: PStringToStringItem;
1399
if Node<>nil then begin
1400
Item:=PStringToStringItem(Node.Data);
1411
constructor TStringToStringTree.Create(CaseSensitive: boolean);
1413
if CaseSensitive then
1414
Create(@CompareStringToStringItems,@ComparePAnsiStringWithStrToStrItem)
1416
Create(@CompareStringToStringItemsI,@ComparePAnsiStringWithStrToStrItemI);
1419
constructor TStringToStringTree.Create(const ACompareItems,
1420
ACompareNameWithItem: TListSortCompare);
1422
FCompareItems:=ACompareItems;
1423
FCompareNameWithItem:=ACompareNameWithItem;
1424
FItems:=TAvgLvlTree.Create(FCompareItems);
1427
destructor TStringToStringTree.Destroy;
1434
procedure TStringToStringTree.Clear;
1436
Node: TAvgLvlTreeNode;
1437
Item: PStringToStringItem;
1439
Node:=FItems.FindLowest;
1440
while Node<>nil do begin
1441
Item:=PStringToStringItem(Node.Data);
1443
Node:=FItems.FindSuccessor(Node);
1448
procedure TStringToStringTree.Assign(Src: TStringToStringTree);
1450
Node: TAvgLvlTreeNode;
1451
Item: PStringToStringItem;
1454
if Src=nil then exit;
1455
Node:=Src.Tree.FindLowest;
1456
while Node<>nil do begin
1457
Item:=PStringToStringItem(Node.Data);
1458
Values[Item^.Name]:=Item^.Value;
1459
Node:=Src.Tree.FindSuccessor(Node);
1463
function TStringToStringTree.Contains(const Name: string): Boolean;
1465
Result:=FindNode(Name)<>nil;
1468
procedure TStringToStringTree.Delete(const Name: string);
1470
Node: TAvgLvlTreeNode;
1471
Item: PStringToStringItem;
1473
Node:=FindNode(Name);
1474
if Node=nil then exit;
1475
Item:=PStringToStringItem(Node.Data);
1476
FItems.Delete(Node);
1480
procedure TStringToStringTree.Add(const Name, Value, Delimiter: string);
1484
OldValue:=Values[Name];
1485
if OldValue<>'' then
1486
OldValue:=OldValue+Delimiter;
1487
OldValue:=OldValue+Value;
1488
Values[Name]:=OldValue;
1491
procedure TStringToStringTree.AddNameValues(List: TStrings);
1495
for i:=0 to List.Count-1 do
1496
Values[List.Names[i]]:=List.ValueFromIndex[i];
1499
procedure TStringToStringTree.AddValues(List: TStrings);
1503
for i:=0 to List.Count-1 do
1504
Values[List[i]]:='';
1507
function TStringToStringTree.GetFirst(out Name, Value: string): Boolean;
1509
Result:=GetNode(Tree.FindLowest,Name,Value);
1512
function TStringToStringTree.GetLast(out Name, Value: string): Boolean;
1514
Result:=GetNode(Tree.FindHighest,Name,Value);
1517
function TStringToStringTree.GetNext(const Name: string; out NextName,
1518
NextValue: string): Boolean;
1520
Node: TAvgLvlTreeNode;
1522
Node:=FindNode(Name);
1524
Node:=Tree.FindSuccessor(Node);
1525
Result:=GetNode(Node,NextName,NextValue);
1528
function TStringToStringTree.GetPrev(const Name: string; out PrevName,
1529
PrevValue: string): Boolean;
1531
Node: TAvgLvlTreeNode;
1533
Node:=FindNode(Name);
1535
Node:=Tree.FindPrecessor(Node);
1536
Result:=GetNode(Node,PrevName,PrevValue);
1540
{ TPointerToPointerTree }
1542
function TPointerToPointerTree.GetCount: Integer;
1544
Result:=FItems.Count;
1547
function TPointerToPointerTree.GetValues(const Key: Pointer): Pointer;
1549
Node: TAvgLvlTreeNode;
1551
Node:=FindNode(Key);
1553
Result:=PPointerToPointerItem(Node.Data)^.Value
1558
procedure TPointerToPointerTree.SetValues(const Key: Pointer;
1559
const AValue: Pointer);
1561
NewItem: PPointerToPointerItem;
1562
Node: TAvgLvlTreeNode;
1564
Node:=FindNode(Key);
1566
PPointerToPointerItem(Node.Data)^.Value:=AValue
1570
NewItem^.Value:=AValue;
1571
FItems.Add(NewItem);
1575
function TPointerToPointerTree.FindNode(const Key: Pointer): TAvgLvlTreeNode;
1577
Result:=FItems.FindKey(Key,@ComparePointerWithPtrToPtrItem)
1580
function TPointerToPointerTree.GetNode(Node: TAvgLvlTreeNode; out Key,
1581
Value: Pointer): Boolean;
1583
Item: PPointerToPointerItem;
1585
if Node<>nil then begin
1586
Item:=PPointerToPointerItem(Node.Data);
1597
constructor TPointerToPointerTree.Create;
1599
FItems:=TAvgLvlTree.Create(@ComparePointerToPointerItems);
1602
destructor TPointerToPointerTree.Destroy;
1609
procedure TPointerToPointerTree.Clear;
1611
Node: TAvgLvlTreeNode;
1612
Item: PPointerToPointerItem;
1614
Node:=FItems.FindLowest;
1615
while Node<>nil do begin
1616
Item:=PPointerToPointerItem(Node.Data);
1618
Node:=FItems.FindSuccessor(Node);
1623
procedure TPointerToPointerTree.Remove(Key: Pointer);
1625
Node: TAvgLvlTreeNode;
1626
Item: PPointerToPointerItem;
1628
Node:=FindNode(Key);
1629
if Node=nil then exit;
1630
Item:=PPointerToPointerItem(Node.Data);
1631
FItems.Delete(Node);
1635
function TPointerToPointerTree.Contains(const Key: Pointer): Boolean;
1637
Result:=FindNode(Key)<>nil;
1640
function TPointerToPointerTree.GetFirst(out Key, Value: Pointer): Boolean;
1642
Result:=GetNode(Tree.FindLowest,Key,Value);
1645
function TPointerToPointerTree.GetLast(out Key, Value: Pointer): Boolean;
1647
Result:=GetNode(Tree.FindHighest,Key,Value);
1650
function TPointerToPointerTree.GetNext(const Key: Pointer; out NextKey,
1651
NextValue: Pointer): Boolean;
1653
Node: TAvgLvlTreeNode;
1655
Node:=FindNode(Key);
1657
Node:=Tree.FindSuccessor(Node);
1658
Result:=GetNode(Node,NextKey,NextValue);
1661
function TPointerToPointerTree.GetPrev(const Key: Pointer; out PrevKey,
1662
PrevValue: Pointer): Boolean;
1664
Node: TAvgLvlTreeNode;
1666
Node:=FindNode(Key);
1668
Node:=Tree.FindPrecessor(Node);
1669
Result:=GetNode(Node,PrevKey,PrevValue);