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