From 065bc9485c4e2e013b1ea1589391a01a765dcb34 Mon Sep 17 00:00:00 2001 From: mattias Date: Sat, 17 Mar 2012 20:38:48 +0000 Subject: [PATCH] avglvltree: use rotateleft/right for balanceafterinsert git-svn-id: trunk@36137 - --- components/lazutils/avglvltree.pas | 149 +++++++++++++++++++++++++---- test/lazutils/testavglvltree.pas | 18 +++- 2 files changed, 143 insertions(+), 24 deletions(-) diff --git a/components/lazutils/avglvltree.pas b/components/lazutils/avglvltree.pas index f142add3f3..03ff5cf813 100644 --- a/components/lazutils/avglvltree.pas +++ b/components/lazutils/avglvltree.pas @@ -16,11 +16,17 @@ Abstract: The Tree is sorted ascending from left to right. That means - Compare(Node.Left,Node.Right) <= 0 for all nodes. + Compare(Node.Left,Node.Right) <= 0 for all nodes. TAvgLvlTree is an Average Level binary Tree. This binary tree is always balanced, so that inserting, deleting and finding a node is performed in O(log(#Nodes)). + + Duplicates are supported. + Order of duplicates is kept, that means the order is stable. + + The compare function must define a total order, that means transitive + A >= B and B>=C means A >= C for all nodes A,B,C } unit AvgLvlTree; @@ -79,11 +85,13 @@ type procedure BalanceAfterInsert(ANode: TAvgLvlTreeNode); procedure BalanceAfterDelete(ANode: TAvgLvlTreeNode); function FindInsertPos(Data: Pointer): TAvgLvlTreeNode; + procedure Init; virtual; + procedure RotateLeft(aNode: TAvgLvlTreeNode); virtual; + procedure RotateRight(aNode: TAvgLvlTreeNode); virtual; procedure SetOnCompare(const AValue: TListSortCompare); procedure SetOnObjectCompare(const AValue: TObjectSortCompare); procedure SetCompares(const NewCompare: TListSortCompare; const NewObjectCompare: TObjectSortCompare); - procedure Init; virtual; public constructor Create(OnCompareMethod: TListSortCompare); constructor CreateObjectCompare(OnCompareMethod: TObjectSortCompare); @@ -847,7 +855,7 @@ begin OldRight:=ANode.Right; if (OldRight.Balance>=0) then begin // OldRight.Balance is 0 or -1 - // rotate left + // rotate ANode,OldRight left OldRightLeft:=OldRight.Left; if (OldParent<>nil) then begin if (OldParent.Left=ANode) then @@ -867,7 +875,19 @@ begin ANode:=OldRight; end else begin // OldRight.Balance=-1 - // double rotate right left + { double rotate + = rotate OldRightLeft,OldRight right + and then rotate ANode,OldRightLeft left + OldParent OldParent + | | + ANode OldRightLeft + \ / \ + OldRight => ANode OldRight + / \ / + OldRightLeft OldRightLeftLeft OldRightLeftRight + / \ + OldRightLeftLeft OldRightLeftRight + } OldRightLeft:=OldRight.Left; OldRightLeftLeft:=OldRightLeft.Left; OldRightLeftRight:=OldRightLeft.Right; @@ -905,7 +925,7 @@ begin // Node is overweighted to the left OldLeft:=ANode.Left; if (OldLeft.Balance<=0) then begin - // rotate right + // rotate OldLeft,ANode right OldLeftRight:=OldLeft.Right; if (OldParent<>nil) then begin if (OldParent.Left=ANode) then @@ -925,7 +945,19 @@ begin ANode:=OldLeft; end else begin // OldLeft.Balance = 1 - // double rotate left right + { double rotate left right + = rotate OldRightLeft,OldRight right + and then rotate ANode,OldRightLeft left + OldParent OldParent + | | + ANode OldLeftRight + / / \ + OldLeft => OldLeft ANode + \ \ / + OldLeftRight OldLeftRightLeft OldLeftRightRight + / \ + OldLeftRightLeft OldLeftRightRight + } OldLeftRight:=OldLeft.Right; OldLeftRightLeft:=OldLeftRight.Left; OldLeftRightRight:=OldLeftRight.Right; @@ -964,8 +996,7 @@ end; procedure TAvgLvlTree.BalanceAfterInsert(ANode: TAvgLvlTreeNode); var - OldParent, OldParentParent, OldRight, OldRightLeft, OldRightRight, OldLeft, - OldLeftLeft, OldLeftRight: TAvgLvlTreeNode; + OldParent, OldRight, OldLeft: TAvgLvlTreeNode; begin OldParent:=ANode.Parent; while (OldParent<>nil) do begin @@ -980,15 +1011,16 @@ begin end; // OldParent.Balance=-2 if (ANode.Balance=-1) then begin - { rotate right + { rotate ANode,ANode.Parent right OldParentParent OldParentParent | | OldParent => ANode / \ - ANode OldParent + ANode OldParent \ / OldRight OldRight } - OldRight:=ANode.Right; + RotateRight(OldParent); + {OldRight:=ANode.Right; OldParentParent:=OldParent.Parent; if (OldParentParent<>nil) then begin // OldParent has GrandParent. GrandParent gets new child @@ -1005,12 +1037,14 @@ begin OldParent.Parent:=ANode; OldParent.Left:=OldRight; if (OldRight<>nil) then - OldRight.Parent:=OldParent; + OldRight.Parent:=OldParent;} + ANode.Balance:=0; OldParent.Balance:=0; end else begin // Node.Balance = +1 - { double rotate = rotate left, right + { double rotate + = rotate ANode,OldRight left and then rotate OldRight,OldParent right OldParentParent OldParentParent | | OldParent OldRight @@ -1021,8 +1055,10 @@ begin / \ OldRightLeft OldRightRight } - OldParentParent:=OldParent.Parent; OldRight:=ANode.Right; + RotateLeft(ANode); + RotateRight(OldParent); + {OldParentParent:=OldParent.Parent; OldRightLeft:=OldRight.Left; OldRightRight:=OldRight.Right; if (OldParentParent<>nil) then begin @@ -1045,7 +1081,8 @@ begin if (OldRightLeft<>nil) then OldRightLeft.Parent:=ANode; if (OldRightRight<>nil) then - OldRightRight.Parent:=OldParent; + OldRightRight.Parent:=OldParent;} + if (OldRight.Balance<=0) then ANode.Balance:=0 else @@ -1068,7 +1105,7 @@ begin end; // OldParent.Balance = +2 if(ANode.Balance=+1) then begin - { rotate left + { rotate OldParent,ANode left OldParentParent OldParentParent | | OldParent => ANode @@ -1076,7 +1113,8 @@ begin ANode OldParent / \ OldLeft OldLeft } - OldLeft:=ANode.Left; + RotateLeft(OldParent); + {OldLeft:=ANode.Left; OldParentParent:=OldParent.Parent; if (OldParentParent<>nil) then begin // Parent has GrandParent. GrandParent gets new child @@ -1093,12 +1131,13 @@ begin OldParent.Parent:=ANode; OldParent.Right:=OldLeft; if (OldLeft<>nil) then - OldLeft.Parent:=OldParent; + OldLeft.Parent:=OldParent;} ANode.Balance:=0; OldParent.Balance:=0; end else begin // Node.Balance = -1 - { double rotate = rotate right, left + { double rotate + = rotate OldLeft,ANode right and then rotate OldParent,OldLeft right OldParentParent OldParentParent | | OldParent OldLeft @@ -1110,7 +1149,10 @@ begin OldLeftLeft OldLeftRight } OldLeft:=ANode.Left; - OldParentParent:=OldParent.Parent; + RotateRight(ANode); + RotateLeft(OldParent); + + {OldParentParent:=OldParent.Parent; OldLeftLeft:=OldLeft.Left; OldLeftRight:=OldLeft.Right; if (OldParentParent<>nil) then begin @@ -1133,7 +1175,8 @@ begin if (OldLeftLeft<>nil) then OldLeftLeft.Parent:=OldParent; if (OldLeftRight<>nil) then - OldLeftRight.Parent:=ANode; + OldLeftRight.Parent:=ANode;} + if (OldLeft.Balance>=0) then ANode.Balance:=0 else @@ -1740,6 +1783,70 @@ begin end; end; +procedure TAvgLvlTree.RotateLeft(aNode: TAvgLvlTreeNode); +{ Parent Parent + | | + Node => OldRight + / \ / + Left OldRight Node + / / \ + OldRightLeft Left OldRightLeft +} +var + OldRight: TAvgLvlTreeNode; + AParent: TAvgLvlTreeNode; + OldRightLeft: TAvgLvlTreeNode; +begin + OldRight:=aNode.Right; + OldRightLeft:=OldRight.Left; + AParent:=aNode.Parent; + if AParent<>nil then begin + if AParent.Left=aNode then + AParent.Left:=OldRight + else + AParent.Right:=OldRight; + end else + fRoot:=OldRight; + OldRight.Parent:=AParent; + aNode.Parent:=OldRight; + aNode.Right:=OldRightLeft; + if OldRightLeft<>nil then + OldRightLeft.Parent:=aNode; + OldRight.Left:=aNode; +end; + +procedure TAvgLvlTree.RotateRight(aNode: TAvgLvlTreeNode); +{ Parent Parent + | | + Node => OldLeft + / \ \ + OldLeft Right Node + \ / \ + OldLeftRight OldLeftRight Right +} +var + OldLeft: TAvgLvlTreeNode; + AParent: TAvgLvlTreeNode; + OldLeftRight: TAvgLvlTreeNode; +begin + OldLeft:=aNode.Left; + OldLeftRight:=OldLeft.Right; + AParent:=aNode.Parent; + if AParent<>nil then begin + if AParent.Left=aNode then + AParent.Left:=OldLeft + else + AParent.Right:=OldLeft; + end else + fRoot:=OldLeft; + OldLeft.Parent:=AParent; + aNode.Parent:=OldLeft; + aNode.Left:=OldLeftRight; + if OldLeftRight<>nil then + OldLeftRight.Parent:=aNode; + OldLeft.Right:=aNode; +end; + procedure TAvgLvlTree.Init; begin FNodeClass:=TAvgLvlTreeNode; diff --git a/test/lazutils/testavglvltree.pas b/test/lazutils/testavglvltree.pas index e035477f23..8ff89e0c20 100644 --- a/test/lazutils/testavglvltree.pas +++ b/test/lazutils/testavglvltree.pas @@ -9,6 +9,8 @@ unit TestAvgLvlTree; {$mode objfpc}{$H+} +{ $DEFINE VerboseTestSequence} + interface uses @@ -29,14 +31,13 @@ implementation { TTestAvgLvlTree } procedure TTestAvgLvlTree.TestSequence(Args: array of const); -{ $DEFINE VerboseTestSequence} var Tree: TAvgLvlTree; i: Integer; Value: LongInt; begin Tree:=TAvgLvlTree.Create; - //writeln(Tree.ReportAsString); + //DebugLn(Tree.ReportAsString); Tree.ConsistencyCheck; for i:=Low(Args) to high(Args) do begin @@ -48,6 +49,7 @@ begin {$ENDIF} Tree.Add(Pointer(Value)); end else begin + Value:=-Value; {$IFDEF VerboseTestSequence} debugln([' remove value ',Value]); {$ENDIF} @@ -60,7 +62,7 @@ begin end; Tree.Clear; - //writeln(Tree.ReportAsString); + //DebugLn(Tree.ReportAsString); Tree.ConsistencyCheck; Tree.Free; @@ -86,6 +88,16 @@ begin // double rotate left, right TestSequence([5,3,4]); + + // test deletes + TestSequence([1,2,3,-1,-2,-3]); + TestSequence([1,2,3,-1,-3,-2]); + TestSequence([1,2,3,-2,-1,-3]); + TestSequence([1,2,3,-2,-3,-1]); + TestSequence([1,2,3,-3,-1,-2]); + TestSequence([1,2,3,-3,-2,-1]); + + // end; initialization