ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

avlsupp.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Runtime Library
00003  * LICENSE:         BSD - See COPYING.ARM in the top level directory
00004  * FILE:            lib/rtl/avlsupp.c
00005  * PURPOSE:         AVL Tree Internal Support Routines/Main Algorithms
00006  * PROGRAMMERS:     ReactOS Portable Systems Group
00007  */
00008 
00009 /* INCLUDES ******************************************************************/
00010 
00011 /* Internal header for table entries */
00012 typedef struct _TABLE_ENTRY_HEADER
00013 {
00014     RTL_BALANCED_LINKS BalancedLinks;
00015     LONGLONG UserData;
00016 } TABLE_ENTRY_HEADER, *PTABLE_ENTRY_HEADER;
00017 
00018 typedef enum _RTL_AVL_BALANCE_FACTOR
00019 {
00020     RtlUnbalancedAvlTree = -2,
00021     RtlLeftHeavyAvlTree,
00022     RtlBalancedAvlTree,
00023     RtlRightHeavyAvlTree,
00024 } RTL_AVL_BALANCE_FACTOR;
00025 
00026 C_ASSERT(RtlBalancedAvlTree == 0);
00027 
00028 /* FUNCTIONS ******************************************************************/
00029 
00030 TABLE_SEARCH_RESULT
00031 FORCEINLINE
00032 RtlpFindAvlTableNodeOrParent(IN PRTL_AVL_TABLE Table,
00033                              IN PVOID Buffer,
00034                              OUT PRTL_BALANCED_LINKS *NodeOrParent)
00035 {
00036     PRTL_BALANCED_LINKS CurrentNode, ChildNode;
00037     RTL_GENERIC_COMPARE_RESULTS Result;
00038 
00039     /* Quick check to see if the table is empty */
00040     if (!Table->NumberGenericTableElements) return TableEmptyTree;
00041 
00042     /* Set the current node */
00043     CurrentNode = RtlRightChildAvl(&Table->BalancedRoot);
00044 
00045     /* Start compare loop */
00046     while (TRUE)
00047     {
00048         /* Compare which side is greater */
00049         Result = RtlpAvlCompareRoutine(Table,
00050                                        Buffer,
00051                                        &((PTABLE_ENTRY_HEADER)CurrentNode)->
00052                                        UserData);
00053         if (Result == GenericLessThan)
00054         {
00055             /* We're less, check if this is the left child */
00056             ChildNode = RtlLeftChildAvl(CurrentNode);
00057             if (ChildNode)
00058             {
00059                 /* Continue searching from this node */
00060                 CurrentNode = ChildNode;
00061             }
00062             else
00063             {
00064                 /* Otherwise, the element isn't in this tree */
00065                 *NodeOrParent = CurrentNode;
00066                 return TableInsertAsLeft;
00067             }
00068         }
00069         else if (Result == GenericGreaterThan)
00070         {
00071             /* We're more, check if this is the right child */
00072             ChildNode = RtlRightChildAvl(CurrentNode);
00073             if (ChildNode)
00074             {
00075                 /* Continue searching from this node */
00076                 CurrentNode = ChildNode;
00077             }
00078             else
00079             {
00080                 /* Otherwise, the element isn't in this tree */
00081                 *NodeOrParent = CurrentNode;
00082                 return TableInsertAsRight;
00083             }
00084         }
00085         else
00086         {
00087             /* We should've found the node */
00088             ASSERT(Result == GenericEqual);
00089 
00090             /* Return node found */
00091             *NodeOrParent = CurrentNode;
00092             return TableFoundNode;
00093         }
00094     }
00095 }
00096 
00097 VOID
00098 FORCEINLINE
00099 RtlPromoteAvlTreeNode(IN PRTL_BALANCED_LINKS Node)
00100 {
00101     PRTL_BALANCED_LINKS ParentNode, SuperParentNode;
00102     PRTL_BALANCED_LINKS *SwapNode1, *SwapNode2;
00103 
00104     /* Grab parents up to 2 levels high */
00105     ParentNode = RtlParentAvl(Node);
00106     SuperParentNode = RtlParentAvl(ParentNode);
00107 
00108     /* Pick which nodes will be rotated */
00109     SwapNode1 = RtlIsLeftChildAvl(Node) ? &ParentNode->LeftChild : &ParentNode->RightChild;
00110     SwapNode2 = RtlIsLeftChildAvl(Node) ? &Node->RightChild : &Node->LeftChild;
00111 
00112     /* Do the rotate, and update the parent and super-parent as needed */
00113     *SwapNode1 = *SwapNode2;
00114     if (*SwapNode1) RtlSetParent(*SwapNode1, ParentNode);
00115     *SwapNode2 = ParentNode;
00116     RtlSetParent(ParentNode, Node);
00117 
00118     /* Now update the super-parent child link, and make it parent of the node*/
00119     SwapNode1 = (RtlLeftChildAvl(SuperParentNode) == ParentNode) ?
00120                  &SuperParentNode->LeftChild: &SuperParentNode->RightChild;
00121     *SwapNode1 = Node;
00122     RtlSetParent(Node, SuperParentNode);
00123 }
00124 
00125 BOOLEAN
00126 FORCEINLINE
00127 RtlpRebalanceAvlTreeNode(IN PRTL_BALANCED_LINKS Node)
00128 {
00129     PRTL_BALANCED_LINKS ChildNode, SubChildNode;
00130     CHAR Balance;
00131     ASSERT(RtlParentAvl(Node) != Node);
00132 
00133     /* Get the balance, and figure out which child node to go down on */
00134     Balance = RtlBalance(Node);
00135     ChildNode = (Balance == RtlRightHeavyAvlTree) ?
00136                  RtlRightChildAvl(Node) : RtlLeftChildAvl(Node);
00137 
00138     /* The child and node have the same balance, promote the child upwards */
00139     if (RtlBalance(ChildNode) == Balance)
00140     {
00141         /* This performs the rotation described in Knuth A8-A10 for Case 1 */
00142         RtlPromoteAvlTreeNode(ChildNode);
00143 
00144         /* The nodes are now balanced */
00145         RtlSetBalance(ChildNode, RtlBalancedAvlTree);
00146         RtlSetBalance(Node, RtlBalancedAvlTree);
00147         return FALSE;
00148     }
00149 
00150     /* The child has the opposite balance, a double promotion of the child's child must happen */
00151     if (RtlBalance(ChildNode) == -Balance)
00152     {
00153         /* Pick which sub-child to use based on the balance */
00154         SubChildNode = (Balance == RtlRightHeavyAvlTree) ?
00155                         RtlLeftChildAvl(ChildNode) : RtlRightChildAvl(ChildNode);
00156 
00157         /* Do the double-rotation described in Knuth A8-A10 for Case 2 */
00158         RtlPromoteAvlTreeNode(SubChildNode);
00159         RtlPromoteAvlTreeNode(SubChildNode);
00160 
00161         /* Was the sub-child sharing the same balance as the node? */
00162         if (RtlBalance(SubChildNode) == Balance)
00163         {
00164             /* Then the subchild is now balanced, and the node's weight is inversed */
00165             RtlSetBalance(ChildNode, RtlBalancedAvlTree);
00166             RtlSetBalance(Node, -Balance);
00167         }
00168         else if (RtlBalance(SubChildNode) == -Balance)
00169         {
00170             /*
00171              * In this case, the sub-child weight was the inverse of the node, so
00172              * the child now shares the node's balance original weight, while the
00173              * node becomes balanced.
00174              */
00175             RtlSetBalance(ChildNode, Balance);
00176             RtlSetBalance(Node, RtlBalancedAvlTree);
00177         }
00178         else
00179         {
00180             /*
00181              * Otherwise, the sub-child was unbalanced, so both the child and node
00182              * now become balanced.
00183              */
00184             RtlSetBalance(ChildNode, RtlBalancedAvlTree);
00185             RtlSetBalance(Node, RtlBalancedAvlTree);
00186         }
00187 
00188         /* In all cases, the sub-child is now balanced */
00189         RtlSetBalance(SubChildNode, RtlBalancedAvlTree);
00190         return FALSE;
00191     }
00192 
00193     /*
00194      * The case that remains is that the child was already balanced, so this is
00195      * This is the rotation required for Case 3 in Knuth A8-A10
00196      */
00197     RtlPromoteAvlTreeNode(ChildNode);
00198 
00199     /* Now the child has the opposite weight of the node */
00200     RtlSetBalance(ChildNode, -Balance);
00201 
00202     /* This only happens on deletion, so we return TRUE to terminate the delete */
00203     return TRUE;
00204 }
00205 
00206 VOID
00207 FORCEINLINE
00208 RtlpInsertAvlTreeNode(IN PRTL_AVL_TABLE Table,
00209                       IN PRTL_BALANCED_LINKS NewNode,
00210                       IN OUT PVOID NodeOrParent,
00211                       IN OUT TABLE_SEARCH_RESULT SearchResult)
00212 {
00213     CHAR Balance;
00214 
00215     /* Initialize the new inserted element */
00216     MI_ASSERT(SearchResult != TableFoundNode);
00217     NewNode->LeftChild = NewNode->RightChild = NULL;
00218     RtlSetBalance(NewNode, RtlBalancedAvlTree);
00219 
00220     /* Increase element count */
00221     Table->NumberGenericTableElements++;
00222 
00223     /* Check where we should insert the entry */
00224     if (SearchResult == TableEmptyTree)
00225     {
00226         /* This is the new root node */
00227         RtlInsertAsRightChildAvl(&Table->BalancedRoot, NewNode);
00228 
00229         /* On AVL trees, we also update the depth */
00230         ASSERT(Table->DepthOfTree == 0);
00231         Table->DepthOfTree = 1;
00232         return;
00233     }
00234     else if (SearchResult == TableInsertAsLeft)
00235     {
00236         /* Insert it left */
00237         RtlInsertAsLeftChildAvl(NodeOrParent, NewNode);
00238     }
00239     else
00240     {
00241         /* Right node */
00242         RtlInsertAsRightChildAvl(NodeOrParent, NewNode);
00243     }
00244 
00245     /* Little cheat to save on loop processing, taken from Timo */
00246     RtlSetBalance(&Table->BalancedRoot, RtlLeftHeavyAvlTree);
00247 
00248     /*
00249      * This implements A6-A7 from Knuth based on http://coding.derkeiler.com
00250      * /pdf/Archive/C_CPP/comp.lang.c/2004-01/1812.pdf, however the algorithm
00251      * is slightly modified to follow the tree based on the Parent Node such
00252      * as the Windows algorithm does it, instead of following the nodes down.
00253      */
00254     while (TRUE)
00255     {
00256         /* Calculate which side to balance on */
00257         Balance = RtlIsLeftChildAvl(NewNode) ? RtlLeftHeavyAvlTree : RtlRightHeavyAvlTree;
00258 
00259         /* Check if the parent node was balanced */
00260         if (RtlBalance(NodeOrParent) == RtlBalancedAvlTree)
00261         {
00262             /* It's not balanced anymore (heavy on one side) */
00263             RtlSetBalance(NodeOrParent, Balance);
00264 
00265             /* Move up */
00266             NewNode = NodeOrParent;
00267             NodeOrParent = RtlParentAvl(NodeOrParent);
00268         }
00269         else if (RtlBalance(NodeOrParent) != Balance)
00270         {
00271             /* The parent's balance is opposite, so the tree is balanced now */
00272             RtlSetBalance(NodeOrParent, RtlBalancedAvlTree);
00273 
00274             /* Check if this is the root (the cheat applied earlier gets us here) */
00275             if (RtlBalance(&Table->BalancedRoot) == RtlBalancedAvlTree)
00276             {
00277                 /* The depth has thus increased */
00278                 Table->DepthOfTree++;
00279             }
00280 
00281             /* We reached the root or a balanced node, so we're done */
00282             break;
00283         }
00284         else
00285         {
00286             /* The tree is now unbalanced, so AVL rebalancing must happen */
00287             RtlpRebalanceAvlTreeNode(NodeOrParent);
00288             break;
00289         }
00290     }
00291 }
00292 
00293 VOID
00294 FORCEINLINE
00295 RtlpDeleteAvlTreeNode(IN PRTL_AVL_TABLE Table,
00296                       IN PRTL_BALANCED_LINKS Node)
00297 {
00298     PRTL_BALANCED_LINKS DeleteNode = NULL, ParentNode;
00299     PRTL_BALANCED_LINKS *Node1, *Node2;
00300     CHAR Balance;
00301 
00302     /* Take one of the children if possible */
00303     if (!(RtlLeftChildAvl(Node)) || !(RtlRightChildAvl(Node))) DeleteNode = Node;
00304 
00305     /* Otherwise, check if one side is longer */
00306     if (!(DeleteNode) && (RtlBalance(Node) >= RtlBalancedAvlTree))
00307     {
00308         /* Pick the successor which will be the longest side in this case */
00309         DeleteNode = RtlRightChildAvl(Node);
00310         while (RtlLeftChildAvl(DeleteNode)) DeleteNode = RtlLeftChildAvl(DeleteNode);
00311     }
00312     else if (!DeleteNode)
00313     {
00314         /* Pick the predecessor which will be the longest side in this case */
00315         DeleteNode = RtlLeftChildAvl(Node);
00316         while (RtlRightChildAvl(DeleteNode)) DeleteNode = RtlRightChildAvl(DeleteNode);
00317     }
00318 
00319     /* Get the parent node */
00320     ParentNode = RtlParentAvl(DeleteNode);
00321     DPRINT("Parent: %p\n", ParentNode);
00322 
00323     /* Pick which now to use based on whether or not we have a left child */
00324     Node1 = RtlLeftChildAvl(DeleteNode) ? &DeleteNode->LeftChild : &DeleteNode->RightChild;
00325     DPRINT("Node 1: %p %p\n", Node1, *Node1);
00326 
00327     /* Pick which node to swap based on if we're already a left child or not */
00328     Node2 = RtlIsLeftChildAvl(DeleteNode) ? &ParentNode->LeftChild : &ParentNode->RightChild;
00329     DPRINT("Node 2: %p %p\n", Node2, *Node2);
00330 
00331     /* Pick the correct balance depending on which side will get heavier */
00332     Balance = RtlIsLeftChildAvl(DeleteNode) ? RtlLeftHeavyAvlTree : RtlRightHeavyAvlTree;
00333     DPRINT("Balance: %lx\n", Balance);
00334 
00335     /* Swap the children nodes, making one side heavier */
00336     *Node2 = *Node1;
00337 
00338     /* If the node has a child now, update its parent */
00339     if (*Node1) RtlSetParent(*Node1, ParentNode);
00340 
00341     /* Assume balanced root for loop optimization */
00342     RtlSetBalance(&Table->BalancedRoot, RtlBalancedAvlTree);
00343 
00344     /* Loop up the tree by parents */
00345     while (TRUE)
00346     {
00347         /* Check if the tree's balance increased */
00348         if (RtlBalance(ParentNode) == Balance)
00349         {
00350             /* Now the tree is balanced */
00351             RtlSetBalance(ParentNode, RtlBalancedAvlTree);
00352         }
00353         else if (RtlBalance(ParentNode) == RtlBalancedAvlTree)
00354         {
00355             /* The tree has now become less balanced, since it was balanced */
00356             RtlSetBalance(ParentNode, -Balance);
00357 
00358             /* Deal with the loop optimization to detect loss of a tree level */
00359             if (RtlBalance(&Table->BalancedRoot) != RtlBalancedAvlTree) Table->DepthOfTree--;
00360             break;
00361         }
00362         else
00363         {
00364             /* The tree has become unbalanced, so a rebalance is needed */
00365             if (RtlpRebalanceAvlTreeNode(ParentNode)) break;
00366 
00367             /* Get the new parent after the balance */
00368             ParentNode = RtlParentAvl(ParentNode);
00369         }
00370 
00371         /* Choose which balance factor to use based on which side we're on */
00372         Balance = RtlIsRightChild(ParentNode) ?
00373                   RtlRightHeavyAvlTree : RtlLeftHeavyAvlTree;
00374 
00375         /* Iterate up the tree */
00376         ParentNode = RtlParentAvl(ParentNode);
00377     }
00378 
00379     /* Check if this isn't the node we ended up deleting directly */
00380     if (Node == DeleteNode) return;
00381 
00382     /* Copy the deleted node itself */
00383     RtlpCopyAvlNodeData(DeleteNode, Node);
00384 
00385     /* Pick the right node to unlink */
00386     Node1 = RtlIsLeftChildAvl(Node) ?
00387             &(RtlParentAvl(DeleteNode))->LeftChild : &(RtlParentAvl(DeleteNode))->RightChild;
00388     *Node1 = DeleteNode;
00389 
00390     /* Reparent as appropriate */
00391     if (RtlLeftChildAvl(DeleteNode)) RtlSetParent(RtlLeftChildAvl(DeleteNode), DeleteNode);
00392     if (RtlRightChildAvl(DeleteNode)) RtlSetParent(RtlRightChildAvl(DeleteNode), DeleteNode);
00393 }
00394 
00395 /* EOF */

Generated on Sun May 27 2012 04:36:21 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.