size : 27357 uploaded_on : Mon Jan 4 00:00:00 1999 modified_on : Wed Dec 8 14:03:31 1999 title : AVL Tree org_filename : AVL.PAS author : Bruce Christensen authoremail : brucec@oanet.com description : AVL trees are binary trees, but should be really called Balanced Binary Trees. They are balanced (or re-balanced) each time there is an node addition/deletion so the right sub-tree of any node has the same number of levels as the left sub-tree (plus or minus one). The "balancing" keeps the binary tree in optimal shape so accessing is as fast as possible. keywords : tested : not tested yet submitted_by : Bruce Christensen submitted_by_email : brucec@oanet.com uploaded_by : nobody modified_by : nobody owner : nobody lang : pas file-type : text/plain category : pascal-alg-sortsearch __END_OF_HEADER__ {*********************************************************************** * * * AVL.PAS * * * * Implements a structure and routines manipulate the balanced * * AVL tree. * * * * Modifications * * ============= * * * ***********************************************************************} Unit AVL ; Interface Uses Printer ; Const Max_Tree_Nodes = 500 ; { Constant is significant only if an ordered } { array of the AVL tree nodes is desired. } Type AVLTreeStr = String[12] ; BalanceSet = (Left_Tilt , Neutral , Right_Tilt) ; AVLDataRec = Record Key : AVLTreeStr ; RecOfs : LongInt ; RecNum : Word ; End ; AVLPtr = ^AVL_Tree_Rec ; AVL_Tree_Rec = Record TreeData : AVLDataRec ; Balance : BalanceSet ; Left , Right : AVLPtr ; End ; TreeRecArray = Array[1..Max_Tree_Nodes] of AVLDataRec ; {.PA} Procedure Insert_AVLTree(Var Root : AVLPtr ; X : AVLDataRec ) ; Function Search_AVLTree(Var Root : AVLPtr ; X : AVLDataRec ) : Boolean ; Function Search( Root : AVLPtr ; Var X : AVLDataRec ) : Boolean ; Procedure AVLSort_To_Array(Var Root : AVLPtr ; Var SortX : TreeRecArray ; Var Count : Word ) ; Function Find_AVLNode(Var Root : AVLPtr ; X : AVLDataRec ) : AVLPtr ; Procedure Delete_AVLTree(Var Root : AVLPtr ; X : AVLDataRec ; Var DelOK : Boolean ) ; Implementation {.PA} {*********************************************************************** * * * Rotate_Right * * * * Re-arranges tree nodes by rotating them to the right. * * * * Modifications * * ============= * * * ***********************************************************************} Procedure Rotate_Right(Var Root : AVLPtr) ; Var Ptr2 , Ptr3 : AVLPtr ; Begin { Rotate_Right } Ptr2 := Root^.Right ; If Ptr2^.Balance = Right_Tilt then Begin Root^.Right := Ptr2^.Left ; Ptr2^.Left := Root ; Root^.Balance := Neutral ; Root := Ptr2 ; End Else Begin Ptr3 := Ptr2^.Left ; Ptr2^.Left := Ptr3^.Right ; Ptr3^.Right := Ptr2 ; Root^.Right := Ptr3^.Left ; Ptr3^.Left := Root ; If Ptr3^.Balance = Left_Tilt then Ptr2^.Balance := Right_Tilt Else Ptr2^.Balance := Neutral ; If Ptr3^.Balance = Right_Tilt then Root^.Balance := Left_Tilt Else Root^.Balance := Neutral ; Root := Ptr3 ; End ; Root^.Balance := Neutral ; End ; { Rotate_Right } {.PA} {*********************************************************************** * * * Rotate_Left * * * * Re-arranges tree nodes by rotating them to the left. * * * * Modifications * * ============= * * * ***********************************************************************} Procedure Rotate_Left(Var Root : AVLPtr) ; Var Ptr2 , Ptr3 : AVLPtr ; Begin { Rotate_Left } Ptr2 := Root^.Left ; If Ptr2^.Balance = Left_Tilt then Begin Root^.Left := Ptr2^.Right; Ptr2^.Right := Root ; Root^.Balance := Neutral ; Root := Ptr2 ; End Else Begin Ptr3 := Ptr2^.Right ; Ptr2^.Right := Ptr3^.Left ; Ptr3^.Left := Ptr2 ; Root^.Left := Ptr3^.Right ; Ptr3^.Right := Root ; If Ptr3^.Balance = Right_Tilt then Ptr2^.Balance := Left_Tilt Else Ptr2^.Balance := Neutral ; If Ptr3^.Balance = Left_Tilt then Root^.Balance := Right_Tilt Else Root^.Balance := Neutral ; Root := Ptr3 ; End ; Root^.Balance := Neutral ; End ; { Rotate_Left } {.PA} {*********************************************************************** * * * Insert_AVL * * * * Workhouse routine to perform node insertion in an AVL tree. * * * * Modifications * * ============= * * * ***********************************************************************} Procedure Insert_AVL(Var Root : AVLPtr ; X : AVLDataRec ; Var InsertedOK : Boolean ) ; Begin { Insert_AVL } If Root = Nil then Begin New(Root) ; With Root^ do Begin TreeData := X ; Left := Nil ; Right := Nil ; Balance := Neutral ; End ; InsertedOK := True ; End Else If X.Key = Root^.TreeData.Key then Begin InsertedOK := False ; Exit ; End Else If X.Key <= Root^.TreeData.Key then Begin Insert_AVL(Root^.Left , X , InsertedOK) ; If InsertedOK then Case Root^.Balance of Left_Tilt : Begin Rotate_Left(Root) ; InsertedOK := False ; End ; Neutral : Root^.Balance := Left_Tilt ; Right_Tilt : Begin Root^.Balance := Neutral ; InsertedOK := False ; End ; End ; { Case Root^.Balance of } End Else Begin Insert_AVL(Root^.Right , X , InsertedOK) ; If InsertedOK then Case Root^.Balance of Left_Tilt : Begin Root^.Balance := Neutral ; InsertedOk := False ; End ; Neutral : Root^.Balance := Right_Tilt ; Right_Tilt : Begin Rotate_Right(Root) ; InsertedOK := False ; End ; End ; { Case Root^.Balance of } End ; End ; { Insert_AVL } {.PA} {*********************************************************************** * * * Insert_AVLTree * * * * Insert a datum into the AVL tree. * * * * Modifications * * ============= * * * ***********************************************************************} Procedure Insert_AVLTree(Var Root : AVLPtr ; X : AVLDataRec ) ; Var InsertedOK : Boolean ; Begin { Insert_AVLTree } InsertedOK := False ; Insert_AVL(Root , X , InsertedOK) ; End ; { Insert_AVLTree } {*********************************************************************** * * * Search * * * * Search for datum in the AVL tree. This interface routine is * * needed because of the recursion involved in Search_AVLTree. * * * * Modifications * * ============= * * * ***********************************************************************} Function Search( Root : AVLPtr ; Var X : AVLDataRec ) : Boolean ; Begin If Search_AVLTree(Root , X) then Begin Move(Root^ , X , SizeOf(AVLDataRec)) ; Search := True ; End Else Search := False ; End ; {*********************************************************************** * * * Search_AVLTree * * * * Search for datum in the AVL tree. * * * * Modifications * * ============= * * * ***********************************************************************} Function Search_AVLTree(Var Root : AVLPtr ; X : AVLDataRec ) : Boolean ; Begin { Search_AVLTree } Search_AVLTree := False ; While Root <> Nil do Begin If X.Key > Root^.TreeData.Key then Root := Root^.Right Else Begin If X.Key < Root^.TreeData.Key then Root := Root^.Left Else { } { A match has been found. } { } Begin Search_AVLTree := True ; Exit ; End ; End ; End ; End ; { Search_AVLTree } {*********************************************************************** * * * Traverse_Tree * * * * Local recursive routine used to traverse the AVL tree. * * * * Modifications * * ============= * * * ***********************************************************************} PROCEDURE Traverse_Tree(Var Root : AVLPtr ; Var SortX : TreeRecArray ; Var Count : Word ) ; Begin { Traverse_Tree } If Root <> Nil then Begin Traverse_Tree(Root^.Left , SortX , Count) ; Inc(Count) ; If Count <= Max_Tree_Nodes then SortX[Count].Key := Root^.TreeData.Key ; Traverse_Tree(Root^.Right , SortX , Count) ; End ; End ; { Traverse_Tree } {*********************************************************************** * * * AVLSort_To_Array * * * * Return the tree data in a sorted vector (array). * * * * Modifications * * ============= * * * ***********************************************************************} Procedure AVLSort_To_Array(Var Root : AVLPtr ; Var SortX : TreeRecArray ; Var Count : Word ) ; Begin { AVLSort_To_Array } Count := 0 ; { Initialize number of array members. } { In-order traverse of the tree. } Traverse_Tree(Root , SortX , Count) ; End ; { AVLSort_To_Array } {.PA} {*********************************************************************** * * * Find_AVLNode * * * * Return the pointer to a node in the AVL tree for a requested * * datum. * * * * Modifications * * ============= * * * ***********************************************************************} Function Find_AVLNode(Var Root : AVLPtr ; X : AVLDataRec ) : AVLPtr ; Var No_Match : Boolean ; Begin { Find_AVLNode } No_Match := True ; While (Root <> Nil) and No_Match do If X.Key > Root^.TreeData.Key then Root := Root^.Right Else If X.Key < Root^.TreeData.Key then Root := Root^.Left Else No_Match := False ; Find_AVLNode := Root ; End ; { Find_AVLNode } {.PA} {*********************************************************************** * * * Balance_Right * * * * Restores the balanced/near balanced state of an AVL tree by * * rebalancing a right subtree. * * * * Modifications * * ============= * * * ***********************************************************************} Procedure Balance_Right(Var Root : AVLPtr ; Var DelOK : Boolean ) ; Var Ptr2 , Ptr3 : AVLPtr ; Balnc2 , Balnc3 : BalanceSet ; Begin { Balance_Right } Case Root^.Balance of Left_Tilt : Root^.Balance := Neutral ; Neutral : Begin Root^.Balance := Right_Tilt ; DelOk := False ; End ; Right_Tilt : Begin Ptr2 := Root^.Right ; Balnc2 := Ptr2^.Balance ; If not (Balnc2 = Left_Tilt) then Begin Root^.Right := Ptr2^.Left ; Ptr2^.Left := Root ; If Balnc2 = Neutral then Begin Root^.Balance := Right_Tilt ; Ptr2^.Balance := Left_Tilt ; DelOk := False ; End Else Begin Root^.Balance := Neutral ; Ptr2^.Balance := Neutral ; End ; Root := Ptr2 ; End Else Begin Ptr3 := Ptr2^.Left ; Balnc3 := Ptr3^.Balance ; Ptr2^.Left := Ptr3^.Right ; Ptr3^.Right := Ptr2 ; Root^.Right := Ptr3^.Left ; Ptr3^.Left := Root ; If Balnc3 = Left_Tilt then Ptr2^.Balance := Right_Tilt Else Ptr2^.Balance := Neutral ; If Balnc3 = Right_Tilt then Root^.Balance := Left_Tilt Else Root^.Balance := Neutral ; Root := Ptr3 ; Ptr3^.Balance := Neutral ; End ; End ; End ; { CAse Root^.Balance of } End ; { Balance_Right } {.PA} {*********************************************************************** * * * Balance_Left * * * * Restores the balanced/near balanced state of an AVL tree by * * rebalancing a left subtree. * * * * Modifications * * ============= * * * ***********************************************************************} Procedure Balance_Left(Var Root : AVLPtr ; Var DelOK : Boolean ) ; Var Ptr2 , Ptr3 : AVLPtr ; Balnc2 , Balnc3 : BalanceSet ; Begin { Balance_Left } Case Root^.Balance of Left_Tilt : Root^.Balance := Neutral ; Neutral : Begin Root^.Balance := Left_Tilt ; DelOk := False ; End ; Right_Tilt : Begin { Right_Tilt } Ptr2 := Root^.Left ; Balnc2 := Ptr2^.Balance ; If not (Balnc2 = Right_Tilt) then Begin Root^.Left := Ptr2^.Right ; Ptr2^.Right := Root ; If Balnc2 = Neutral then Begin Root^.Balance := Left_Tilt ; Ptr2^.Balance := Right_Tilt ; DelOk := False ; End Else Begin Root^.Balance := Neutral ; Ptr2^.Balance := Neutral ; End ; Root := Ptr2 ; End Else Begin Ptr3 := Ptr2^.Right ; Balnc3 := Ptr3^.Balance ; Ptr2^.Right := Ptr3^.Left ; Ptr3^.Left := Ptr2 ; Root^.Left := Ptr3^.Right ; Ptr3^.Right := Root ; If Balnc3 = Right_Tilt then Ptr2^.Balance := Left_Tilt Else Ptr2^.Balance := Neutral ; If Balnc3 = Left_Tilt then Root^.Balance := Right_Tilt Else Root^.Balance := Neutral ; Root := Ptr3 ; Ptr3^.Balance := Neutral ; End ; End ; { Right_Tilt } End ; { Case Root^.Balance of } End ; { Balance_Left } {.PA} {*********************************************************************** * * * Delete_Both_Children * * * * Delete a node with two empty subtrees. * * * * Modifications * * ============= * * * ***********************************************************************} Procedure Delete_Both_Children(Var Root , Ptr : AVLPtr ; Var DelOK : Boolean ) ; Begin { Delete_Both_Children } If Ptr^.Right = Nil then Begin Root^.TreeData := Ptr^.TreeData ; Ptr := Ptr^.Left ; DelOk := True ; End Else Begin Delete_Both_Children(Root , Ptr^.Right , DelOK) ; If DelOk then Balance_Left(Ptr , DelOK) ; End ; End ; { Delete_Both_Children } {.PA} {*********************************************************************** * * * Delete_AVL * * * * Recursive routine used for node deletion. * * * * Modifications * * ============= * * * ***********************************************************************} Procedure Delete_AVL(Var Root : AVLPtr ; X : AVLDataRec ; Var DelOK : Boolean ) ; Var Ptr : AVLPtr ; Begin { Delete_AVL } If Root = Nil then DelOK := False Else If X.Key < Root^.TreeData.Key then Begin Delete_AVL(Root^.Left , X , DelOK) ; If DelOK then Balance_Right(Root , DelOK) ; End Else If X.Key > Root^.TreeData.Key then Begin Delete_AVL(Root^.Right , X , DelOK) ; If DelOK then Balance_Left(Root , DelOK) ; End Else Begin Ptr := Root ; If Root^.Right = Nil then Begin Root := Root^.Left ; DelOK := True ; End Else Begin Delete_Both_Children(Root , Root^.Left , DelOK) ; If DelOK then Balance_Right(Root , DelOK) ; End ; End ; Dispose(Ptr) ; End ; { Delete_AVL } {.PA} {*********************************************************************** * * * Delete_AVLTree * * * * Deletes the key of X if it is present in the AVL tree. * * * * Modifications * * ============= * * * ***********************************************************************} Procedure Delete_AVLTree(Var Root : AVLPtr ; X : AVLDataRec ; Var DelOK : Boolean ) ; Begin { Delete_AVLTree } DelOK := False ; Delete_AVL(Root , X , DelOK) ; End ; { Delete_AVLTree } Begin { AVL_Tree } End. { AVL_Tree }