avl.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2003, The EROS Group, LLC and Johns Hopkins
00003  * University. All rights reserved.
00004  * 
00005  * This software was developed to support the EROS secure operating
00006  * system project (http://www.eros-os.org). The latest version of
00007  * the OpenCM software can be found at http://www.opencm.org.
00008  * 
00009  * Redistribution and use in source and binary forms, with or
00010  * without modification, are permitted provided that the following
00011  * conditions are met:
00012  * 
00013  * 1. Redistributions of source code must retain the above copyright
00014  *    notice, this list of conditions and the following disclaimer.
00015  * 
00016  * 2. Redistributions in binary form must reproduce the above
00017  *    copyright notice, this list of conditions and the following
00018  *    disclaimer in the documentation and/or other materials
00019  *    provided with the distribution.
00020  * 
00021  * 3. Neither the name of the The EROS Group, LLC nor the name of
00022  *    Johns Hopkins University, nor the names of its contributors
00023  *    may be used to endorse or promote products derived from this
00024  *    software without specific prior written permission.
00025  * 
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
00027  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
00028  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00029  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00030  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
00031  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00032  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00033  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00034  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00035  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00036  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00037  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00038  * POSSIBILITY OF SUCH DAMAGE.
00039  */
00040 
00041 #include <opencm.hxx>
00042 
00043 #include <stddef.h>
00044 #include <stdlib.h>
00045 #include <assert.h>
00046 #include <stdlib.h>
00047 #ifdef AVL_TEST
00048 #include <stdio.h>
00049 #include <getopt.h>
00050 #endif
00051 
00052 #ifndef max
00053 #define max(a,b) (((a) < (b)) ? (b) : (a))
00054 #endif
00055 
00056 #ifndef abs
00057 #define abs(a) (((a) >= 0) ? (a) : - (a))
00058 #endif
00059 
00060 #ifndef TRUE
00061 #define TRUE 1
00062 #endif
00063 
00064 #ifndef FALSE
00065 #define FALSE 0
00066 #endif
00067 
00068 AvlTree<int> avli;
00069 AvlMap<int,const char *> avlm;
00070 
00071 BaseAvlNode::BaseAvlNode()
00072 {
00073   lchild = 0;
00074   rchild = 0;
00075   balance = 0;
00076 }
00077 
00078 BaseAvlNode::~BaseAvlNode()
00079 {
00080 }
00081 
00082 BaseAvlTree::BaseAvlTree(int (*cmp)(const BaseAvlNode& n1, 
00083                                     const BaseAvlNode& n2))
00084 {
00085   cmpfn = cmp;
00086   root = 0;
00087 }
00088 
00089 BaseAvlTree::~BaseAvlTree()
00090 {
00091   BaseAvlNode *nd;
00092 
00093   while ((nd = choose()))
00094     remove(*nd);
00095 }
00096 
00097 #define isBalanced(nd) ((nd == 0) || (nd->balance == 0))
00098 
00106 BaseAvlNode *
00107 BaseAvlNode::left_rotate(BaseAvlNode *A)
00108 {
00109   BaseAvlNode *C;
00110   BaseAvlNode *D;
00111   assert(A->rchild != NULL);
00112 
00113   /* Should only be doing left_rotate when we are right-heavy. */
00114   assert(A->balance > 0);
00115 
00116   C = A->rchild;
00117   D = C->lchild;
00118 
00119   C->lchild = A;
00120   A->rchild = D;
00121 
00122   return C;
00123 }
00124 
00132 BaseAvlNode *
00133 BaseAvlNode::right_rotate(BaseAvlNode *A)
00134 {
00135   BaseAvlNode *B, *E;
00136 
00137   assert(A->lchild != NULL);
00138 
00139   /* Should only be doing right_rotate when we are left-heavy. */
00140   assert(A->balance < 0);
00141 
00142   B = A->lchild;
00143   E = B->rchild;
00144 
00145   B->rchild = A;
00146   A->lchild = E;
00147 
00148   return B;
00149 }
00150 
00155 int
00156 BaseAvlNode::rebalance_right(BaseAvlNode **theRoot)
00157 {
00158   BaseAvlNode *A = *theRoot;
00159   BaseAvlNode *C = A->rchild;
00160   BaseAvlNode *newTree;
00161 
00162   assert (C != NULL);
00163 
00164   if (C->balance < 0) {
00174     BaseAvlNode *D = A->rchild->lchild;
00175     A->rchild = right_rotate(C);
00176     newTree = left_rotate(A);
00177 
00178     switch(D->balance) {
00179     case -1:
00180       C->balance = 1;
00181       A->balance = 0;
00182       break;
00183     case 0:
00184       C->balance = 0;
00185       A->balance = 0;
00186       break;
00187     case 1:
00188       C->balance = 0;
00189       A->balance = -1;
00190       break;
00191     }
00192 
00193     D->balance = 0;
00194     *theRoot = newTree;
00195     return 1;                   /* tree height changed */
00196   }
00197   else {
00206     newTree = left_rotate(A);
00207 
00208     /* If right subtree (previously C, now A) was balanced, then
00209        ht(D)==ht(E) > ht(B). and resulting tree is now left heavy. */
00210     if (C->balance == 0) {
00211       newTree->balance = -1;
00212       A->balance = 1;
00213 
00214       *theRoot = newTree;
00215       return 0;                 /* Tree height unchanged */
00216     }
00217     else { /* C->balance == 1 */
00218       newTree->balance = 0;
00219       A->balance = 0;
00220       *theRoot = newTree;
00221 
00222       return 1;                 /* Tree height changed */
00223     }
00224   }
00225 }
00226 
00231 int
00232 BaseAvlNode::rebalance_left(BaseAvlNode **theRoot)
00233 {
00234   BaseAvlNode *A = *theRoot;
00235   BaseAvlNode *B = A->lchild;
00236   BaseAvlNode *newTree;
00237 
00238   if (B->balance > 0) {
00248     BaseAvlNode *E = A->lchild->rchild;
00249 
00250     A->lchild = left_rotate(B);
00251 
00252     newTree = right_rotate(A);
00253 
00254     switch(E->balance) {
00255     case -1:
00256       B->balance = 0;
00257       A->balance = 1;
00258       break;
00259     case 0:
00260       B->balance = 0;
00261       A->balance = 0;
00262       break;
00263     case 1:
00264       B->balance = -1;
00265       A->balance = 0;
00266       break;
00267     }
00268 
00269     E->balance = 0;
00270     *theRoot = newTree;
00271 
00272     return 1;                   /* Tree height changed */
00273   } else {
00282     newTree = right_rotate(A);
00283 
00284     if (B->balance == 0) {
00285       newTree->balance = 1;
00286       A->balance = -1;
00287 
00288       *theRoot = newTree;
00289       return 0;                 /* Tree height unchanged */
00290     }
00291     else {
00292       newTree->balance = 0;
00293       A->balance = 0;
00294 
00295       *theRoot = newTree;
00296       return 1;                 /* Tree height changed */
00297     }
00298   }
00299 }
00300 
00301 /* avl_do_insert: insert new node into subtree rooted at /^root/,
00302    returns 1 if tree has grown taller, 0 otherwise. */
00303 int
00304 BaseAvlTree::do_insert(BaseAvlNode **theRoot, BaseAvlNode *nd)
00305 {
00306   if ((*theRoot) == NULL) {
00307     *theRoot = nd;
00308     return 1;                   /* tree has grown taller */
00309   }
00310 
00311   {
00312     int cmp = cmpfn(**theRoot, *nd);
00313     if (cmp > 0) {
00314       if (do_insert(&(*theRoot)->lchild, nd)) {
00315         /* If resulting left subtree is imbalanced, then previously must
00316            have been balanced. Add weight to the left. */
00317         (*theRoot)->balance--;
00318 
00319         switch ( (*theRoot)->balance ) {
00320         case 0:
00321           return 0;
00322         case -1:
00323           return 1;
00324         case -2:
00325           (void) BaseAvlNode::rebalance_left(theRoot);
00326           return 0;
00327         case 1:
00328           /* The double rotate case can return with a positive balance
00329              of 1 */
00330           return 0;
00331         default:
00332           assert(FALSE);
00333         }
00334       }
00335     }
00336     else if (cmp < 0) {
00337       if (do_insert(&(*theRoot)->rchild, nd)) {
00338         /* Symmetric with above */
00339 
00340         /* If resulting right subtree is imbalanced, then previously must
00341            have been balanced. Add weight to the right. */
00342         (*theRoot)->balance++;
00343 
00344         switch( (*theRoot)->balance ) {
00345         case 0:
00346           return 0;
00347         case 1:
00348           return 1;
00349         case 2:
00350           (void) BaseAvlNode::rebalance_right(theRoot);
00351           return 0;
00352         case -1:
00353           /* The double rotate case can return a root balance of -1 */
00354           return 0;
00355         default:
00356           assert(FALSE);
00357         }
00358       }
00359     }
00360   }
00361 
00362   /* No change (bogus insert). Tree may have been unbalanced before,
00363      but if so we have already taken the necessary corrective
00364      action. Return 0 to suppress any further tree twirling. */
00365   return 0;
00366 }
00367 
00368 void 
00369 BaseAvlTree::insert(BaseAvlNode *nd)
00370 {
00371   nd->balance = 0;
00372   nd->lchild = NULL;
00373   nd->rchild = NULL;
00374   
00375   do_insert(&root, nd);
00376 }
00377 
00378 BaseAvlNode** 
00379 BaseAvlTree::find_greatest(BaseAvlNode**pnd)
00380 {
00381   while ((*pnd)->rchild)
00382     pnd = &(*pnd)->rchild;
00383 
00384   return pnd;
00385 }
00386 
00387 /* avl_do_remove: delete node from subtree rooted at /^root/,
00388    returns 1 if tree has grown shorter, 0 otherwise. */
00389 int
00390 BaseAvlTree::do_remove(BaseAvlNode **theRoot, BaseAvlNode *nd)
00391 {
00392   if ((*theRoot) == NULL) {
00393     *theRoot = nd;
00394     nd->balance = 0;
00395     nd->lchild = NULL;
00396     nd->rchild = NULL;
00397 
00398     return 0;                   /* was not found */
00399   }
00400 
00401   {
00402     int cmp = cmpfn(**theRoot, *nd);
00403     if (cmp > 0) {
00404       if (do_remove(&(*theRoot)->lchild, nd)) {
00405         /* Removed from left tree and left tree grew shorter */
00406         (*theRoot)->balance++;
00407 
00408         assert ( (*theRoot)->balance >= 0 );
00409 
00410         /* If our balance is now zero, then we shrunk. */
00411         if ( (*theRoot)->balance == 0)
00412           return 1;
00413         /* If our balance is now mildly right-leaning, then we haven't
00414            shrunk. */
00415         if ( (*theRoot)->balance == 1)
00416           return 0;
00417 
00418         assert ( (*theRoot)->balance == 2);
00419         return BaseAvlNode::rebalance_right(theRoot);
00420       }
00421     }
00422     else if (cmp < 0) {
00423       if (do_remove(&(*theRoot)->rchild, nd)) {
00424         /* Symmetric with above */
00425 
00426         /* Removed from right tree and right tree grew shorter */
00427         (*theRoot)->balance--;
00428 
00429         assert ( (*theRoot)->balance <= 0 );
00430 
00431         /* If our balance is now zero, then we shrunk. */
00432         if ( (*theRoot)->balance == 0)
00433           return 1;
00434 
00435         /* If our balance is now mildly right-leaning, then we haven't
00436            shrunk. */
00437         if ( (*theRoot)->balance == -1)
00438           return 0;
00439 
00440         assert ( (*theRoot)->balance == -2);
00441         return BaseAvlNode::rebalance_left(theRoot);
00442       }
00443     }
00444     else {
00445       assert(nd == *theRoot);
00446 
00447       /* This is the node we wish to remove. If either of it's
00448          children is NULL, then keep the other child and indicate that
00449          the tree has shrunk. */
00450       if (nd->lchild == NULL) {
00451         *theRoot = nd->rchild;
00452         return 1;
00453       }
00454 
00455       if (nd->rchild == NULL) {
00456         *theRoot = nd->lchild;
00457         return 1;
00458       }
00459 
00460       /* Both subtrees are occupied. Proceed as follows:
00461        *
00462        * Proceed as follows: Choose either the left or right subtree
00463        * arbitrarily (I chose left). Find the node within that tree
00464        * that is lexically adjacent to the node we want to delete
00465        * (either the greatest node in the left tree or the least node
00466        * in the right tree) and EXCHANGE that node with the node that
00467        * we want to delete. While the overall tree rooted here is now
00468        * temporarily wrong, both the tree rooted at lchild and the
00469        * tree rooted at rchild remain proper AVL trees. Once we finish
00470        * deleting the dead node, the entire tree will once again be
00471        * correct. 
00472        *
00473        * Having swapped them, proceed with the delete in the left
00474        * subtree, and then rebalance *theRoot according to whether the
00475        * left subtree has shrunk. */
00476 
00477       {
00478         BaseAvlNode **ppVictim = find_greatest(&nd->lchild);
00479         BaseAvlNode *victim = *ppVictim;
00480         BaseAvlNode *vlchild = victim->lchild;
00481         BaseAvlNode *vrchild = victim->rchild; /* should be null! */
00482         BaseAvlNode *ndlchild = nd->lchild;
00483         int victimBalance = victim->balance;
00484 
00485         assert(vrchild == NULL);
00486 
00487         /* Move the victim up into the position that /nd/ now occupies */
00488         *theRoot = victim;
00489         victim->rchild = nd->rchild;
00490         nd->lchild = vlchild;
00491         nd->rchild = vrchild;   /* ought to be null */
00492         victim->balance = nd->balance;
00493         nd->balance = victimBalance;
00494 
00495         /* Need to be careful if victim was nd->lchild, because if
00496            that is the case then we have already overwritten the
00497            pointer slot when we clobbered nd->lchild: */
00498         if (&nd->lchild == ppVictim) {
00499           victim->lchild = nd;
00500         }
00501         else {
00502           victim->lchild = ndlchild;
00503           (*ppVictim) = nd;
00504         }
00505 
00506         if (do_remove(&(*theRoot)->lchild, nd)) {
00507           /* Removed from left tree and left tree grew shorter */
00508           (*theRoot)->balance++;
00509 
00510           assert ( (*theRoot)->balance >= 0 );
00511 
00512           /* If our balance is now zero, then we shrunk. */
00513           if ( (*theRoot)->balance == 0)
00514             return 1;
00515           /* If our balance is now mildly right-leaning, then we haven't
00516              shrunk. */
00517           if ( (*theRoot)->balance == 1)
00518             return 0;
00519 
00520           assert ( (*theRoot)->balance == 2);
00521           return BaseAvlNode::rebalance_right(theRoot);
00522         }
00523       }
00524     }
00525   }
00526 
00527   /* No change (bogus insert). Tree may have been unbalanced before,
00528      but if so we have already taken the necessary corrective
00529      action. Return 0 to suppress any further tree twirling. */
00530   return 0;
00531 }
00532 
00533 /* Remove a node from an AVL tree. */
00534 void
00535 BaseAvlTree::remove(BaseAvlNode& key)
00536 {
00537   BaseAvlNode *nd;
00538 
00539   /* Passed /nd/ value may actually be a key, and the do_remove()
00540      logic wants an honest node pointer. Do a lookup first to get a
00541      known-valid node pointer: */
00542 
00543   nd = lookup(key);
00544 
00545   if (nd)
00546     do_remove(&root, nd);
00547 }
00548 
00549 BaseAvlNode *
00550 BaseAvlTree::lookup(const BaseAvlNode& key)
00551 {
00552   BaseAvlNode *theRoot = root;
00553 
00554   for (;theRoot != NULL;) {
00555     int cmp = cmpfn(*theRoot, key);
00556 
00557     if (cmp == 0)
00558       return theRoot;
00559     else if (cmp < 0)
00560       theRoot = theRoot->rchild;
00561     else
00562       theRoot = theRoot->lchild;
00563   }
00564 
00565   return NULL;                  /* not found */
00566 }
00567 
00568 BaseAvlNode *
00569 BaseAvlTree::lookupGLE(const BaseAvlNode& key)
00570 {
00571   BaseAvlNode *theRoot = root;
00572   BaseAvlNode *greatest = NULL;
00573 
00574   for (;theRoot != NULL;) {
00575     int cmp = cmpfn(*theRoot, key);
00576 
00577     /* Exact match must be the greatest key less than or equal to
00578        search key */
00579     if (cmp == 0)
00580       return theRoot;
00581 
00582     /* We're only interested in less than */
00583     if (cmp < 0) {
00584 
00585       /* Update the greatest so far */
00586       greatest = theRoot;
00587 
00588       /* Move right */
00589       theRoot = theRoot->rchild;
00590     } else
00591       theRoot = theRoot->lchild;
00592   }
00593   return greatest;
00594 }
00595 
00596 BaseAvlNode *
00597 BaseAvlTree::choose()
00598 {
00599   return root;
00600 }
00601 
00602 BaseAvlNode *
00603 BaseAvlTree::least()
00604 {
00605   BaseAvlNode *nd = root;
00606 
00607   if (nd == NULL)
00608     return NULL;
00609 
00610   while (nd->lchild)
00611     nd = nd->lchild;
00612 
00613   return nd;
00614 }
00615 
00616 BaseAvlNode *
00617 BaseAvlTree::greatest()
00618 {
00619   BaseAvlNode *nd = root;
00620 
00621   if (nd == NULL)
00622     return NULL;
00623 
00624   while (nd->rchild)
00625     nd = nd->rchild;
00626 
00627   return nd;
00628 }
00629 
00630 /* This is really sleazy. We want an interator that will iterate over
00631  * all of the elements of a tree exactly once, where the iterator
00632  * function is entitled to insert or delete elements from the
00633  * tree. The problem is that the new elements might be inserted before
00634  * any current index into the tree structure, and the "exactly once"
00635  * rule precludes backing up.
00636  *
00637  * What we do is build a temporary internal tree, process each node by
00638  * first removing it, processing it, and then inserting it into the
00639  * output tree. Finally, we clobber the original tree with the content
00640  * of the output tree.
00641  *
00642  * Note the assignment to out.root at the end. This is to deal with
00643  * "owning" containers. At the end of the function the 'out' tree is
00644  * bitwise identical to the '*this' tree, and only the '*this' tree
00645  * will survive. We don't want the elements (which are aliased at that
00646  * point) deleted.
00647  */
00648 void 
00649 BaseAvlTree::iterate(AvlIterFunc avlFunc)
00650 {
00651   BaseAvlTree out = *this;
00652   BaseAvlNode *nd;
00653 
00654   out.root = NULL;
00655 
00656   while ((nd = choose())) {
00657     do_remove(&root, nd);
00658     if (avlFunc(*nd))
00659       out.insert(nd);
00660   }
00661 
00662   *this = out;
00663   out.root = NULL;              // ensure no destruction of nodes!
00664 }
00665 
00666 #ifdef AVL_TEST
00667 static int verbose;
00668 #define VERBOSE if(verbose)
00669 
00671 static int
00672 avl_height(BaseAvlNode *nd)
00673 {
00674   int lheight;
00675   int rheight;
00676 
00677   if (nd == NULL)
00678     return 0;
00679 
00680   lheight = avl_height(nd->lchild);
00681   rheight = avl_height(nd->rchild);
00682   
00683   return max(lheight, rheight) + 1;
00684 }
00685 
00687 static int
00688 avl_validate_balance(BaseAvlNode *nd)
00689 {
00690   int lheight;
00691   int rheight;
00692 
00693   if (nd == NULL)
00694     return TRUE;
00695 
00696   lheight = avl_height(nd->lchild);
00697   rheight = avl_height(nd->rchild);
00698 
00699   if (abs(lheight - rheight) > 1)
00700     return FALSE;
00701 
00702   if (lheight == rheight && nd->balance != 0)
00703     return FALSE;
00704 
00705   if (lheight > rheight && nd->balance != -1)
00706     return FALSE;
00707 
00708   if (lheight < rheight && nd->balance != 1)
00709     return FALSE;
00710 
00711   if (!avl_validate_balance(nd->lchild))
00712     return FALSE;
00713 
00714   if (!avl_validate_balance(nd->rchild))
00715     return FALSE;
00716 
00717   return TRUE;
00718 }
00719 
00720 /* Helper routine for the structure validation logic. Idea is to first
00721    set the user fields to a known value, then to set them to a second
00722    known value but check for them already being that value to identify
00723    cycles. */
00724 static int
00725 avl_setuser(BaseAvlNode *nd, unsigned short user, int shouldCheck)
00726 {
00727   if (nd == NULL)
00728     return TRUE;
00729 
00730   if (shouldCheck && nd->user == user)
00731     return FALSE;
00732 
00733   nd->user = user;
00734   if (avl_setuser(nd->lchild, user, shouldCheck) &&
00735       avl_setuser(nd->rchild, user, shouldCheck))
00736     return TRUE;
00737 
00738   return FALSE;
00739 }
00740 
00742 static int
00743 avl_validate_structure(BaseAvlNode *nd)
00744 {
00745   avl_setuser(nd, 0, FALSE);
00746 
00747   return avl_setuser(nd, 1, TRUE);
00748 }
00749 
00750 static int
00751 avl_validate(AvlTree *tree)
00752 {
00753   /* Must validate structure first */
00754   if (!avl_validate_structure(tree->root)) {
00755     fprintf(stderr, "Tree contains circularities\n");
00756     return FALSE;
00757   }
00758 
00759   if (!avl_validate_balance(tree->root)) {
00760     fprintf(stderr, "Tree balance fields are wrong\n");
00761     return FALSE;
00762   }
00763 
00764   return TRUE;
00765 }
00766 
00767 static void 
00768 do_avl_dump(FILE *out, BaseAvlNode *nd, void (*show)(FILE *, BaseAvlNode *), 
00769             int depth)
00770 {
00771   int i;
00772 
00773   if (nd && nd->rchild)
00774     do_avl_dump(out, nd->rchild, show, depth + 2);
00775   
00776   for (i = 0; i < depth; i++)
00777     fputc(' ', out);
00778   show(out, nd);
00779 
00780   if (nd && nd->lchild)
00781     do_avl_dump(out, nd->lchild, show, depth + 2);
00782 }
00783 
00784 void 
00785 avl_dump(FILE *out, AvlTree *tree, void (*show)(FILE *, BaseAvlNode *))
00786 {
00787   int good = avl_validate(tree);
00788 
00789   do_avl_dump(out, tree->root, show, 0);
00790   fprintf(out, "\n");
00791   assert(good);
00792 }
00793 
00794 typedef struct MyNode MyNode;
00795 struct MyNode {
00796   BaseAvlNode avl;
00797   int key;
00798 };
00799 
00800 static int
00801 mycmp(BaseAvlNode *an1, BaseAvlNode *an2)
00802 {
00803   MyNode *n1 = (MyNode *) an1;
00804   MyNode *n2 = (MyNode *) an2;
00805 
00806   if (n1->key < n2->key)
00807     return -1;
00808   else if (n1->key > n2->key)
00809     return 1;
00810   else
00811     return 0;
00812 }
00813 
00814 static BaseAvlNode *
00815 make_node(int i)
00816 {
00817   MyNode *nd = calloc(1, sizeof(MyNode));
00818   nd->key = i;
00819   return (BaseAvlNode *) nd;
00820 }
00821 
00822 static void
00823 myshow(FILE *out, BaseAvlNode *and)
00824 {
00825   MyNode *nd = (MyNode *) and;
00826   char balance = 'b';
00827 
00828   if (nd && and->balance < 0)
00829     balance = 'l';
00830   if (nd && and->balance > 0)
00831     balance = 'r';
00832 
00833   if (nd)
00834     fprintf(out, "0x%08x [%c]: %d\n", (unsigned) nd, balance, nd->key);
00835   else
00836     fprintf(out, "0x%08x [b]\n", (unsigned) nd);
00837 
00838   fflush(out);
00839 }
00840 
00841 /* Eight values ought to be sufficient to generate all possible
00842    insertion permutations, but I'm using 10 because I want to make
00843    sure that all of the delete permutations are done correctly. This
00844    takes an incredibly long time to run, since it runs all
00845    permutations on 10 inputs, which takes O(10!)
00846    operations. Fortunately, we only run this when something is
00847    broken. */
00848 int values[] =  { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1 };
00849 
00850 void
00851 tree_test(AvlTree *tree)
00852 {
00853   int i;
00854   for (i = 1; values[i] >= 0; i++) {
00855     if (values[i] == 0)
00856       continue;
00857 
00858     int thisValue = values[i];
00859     values[i] = 0;
00860 
00861     BaseAvlNode *nd = make_node(thisValue);
00862 
00863     VERBOSE fprintf(stdout, "OP: Insert %d (0x%08x)\n", thisValue, 
00864                     (unsigned) nd);
00865     VERBOSE fflush(stdout);
00866     avl_insert(tree, nd);
00867 
00868     VERBOSE avl_dump(stdout, tree, myshow);
00869     assert (avl_validate(tree));
00870 
00871     {
00872       MyNode lookup_nd;
00873       BaseAvlNode *theNode;
00874       lookup_nd.key = thisValue;
00875 
00876       theNode = avl_lookup(tree, (BaseAvlNode *) &lookup_nd);
00877       VERBOSE fprintf(stdout, "CHECK: lookup %d (0x%08x)\n", thisValue, 
00878                       (unsigned) theNode);
00879       VERBOSE fflush(stdout);
00880 
00881       assert(theNode == nd);
00882     }
00883 
00884 
00885     tree_test(tree);
00886 
00887     VERBOSE fprintf(stdout, "OP: Remove %d (0x%08x)\n", thisValue, 
00888                     (unsigned) nd);
00889     VERBOSE fflush(stdout);
00890 
00891     {
00892       MyNode lookup_nd;
00893       BaseAvlNode *theNode;
00894       lookup_nd.key = thisValue;
00895 
00896       theNode = avl_lookup(tree, (BaseAvlNode *) &lookup_nd);
00897       VERBOSE fprintf(stdout, "CHECK: lookup %d (0x%08x)\n", thisValue, 
00898                       (unsigned) theNode);
00899       VERBOSE fflush(stdout);
00900 
00901       assert(theNode == nd);
00902     }
00903 
00904     avl_remove(tree, nd);
00905     VERBOSE avl_dump(stdout, tree, myshow);
00906     assert (avl_validate(tree));
00907 
00908     free(nd);
00909 
00910     values[i] = thisValue;
00911   }
00912 }
00913 
00914 /* This is a test harness helper. If the big ugly test above fails,
00915    pipe its output to 'grep OP' and then list the failing sequence of
00916    operations here as follows:
00917 
00918    inserts become positive entries
00919    deletes become negative entries
00920    end of list is represented by zero.
00921 
00922    This will allow you to replay the failing sequence (which could be
00923    very long) up to the moment before the disaster within a debugger,
00924    whereupon you can try to figure out what in hell was going on. */
00925 int op[] = { 2, 3, 4, 5, 6, 7, -7, -6, 7, 6, -6, -7, -5, 6, 5, 7, -7, -5, 0 };
00926 
00927 void 
00928 specific_test(AvlTree *tree)
00929 {
00930   int i = 0;
00931 
00932   for (i = 0; op[i]; i++) {
00933     int thisValue = abs(op[i]);
00934     if (op[i] > 0) {
00935       BaseAvlNode *nd = make_node(thisValue);
00936       fprintf(stdout, "OP %d: Insert %d (0x%08x)\n", i, thisValue, (unsigned) nd);
00937       fflush(stdout);
00938       avl_insert(tree, nd);
00939 
00940       {
00941         MyNode lookup_nd;
00942         BaseAvlNode *theNode;
00943         lookup_nd.key = thisValue;
00944 
00945         theNode = avl_lookup(tree, (BaseAvlNode *) &lookup_nd);
00946         fprintf(stdout, "CHECK: lookup %d (0x%08x)\n", thisValue, (unsigned) theNode);
00947 
00948         avl_dump(stdout, tree, myshow);
00949         assert (avl_validate(tree));
00950         assert(theNode == nd);
00951       }
00952     }
00953     else {
00954       MyNode lookup_nd;
00955       lookup_nd.key = thisValue;
00956 
00957       BaseAvlNode *nd = avl_lookup(tree, (BaseAvlNode *) &lookup_nd);
00958 
00959       fprintf(stdout, "OP %d: Remove %d (0x%08x)\n", i, thisValue, (unsigned) nd);
00960       fflush(stdout);
00961 
00962       avl_remove(tree, nd);
00963 
00964       avl_dump(stdout, tree, myshow);
00965       assert (avl_validate(tree));
00966     }
00967   }
00968 }
00969 
00970 int 
00971 main(int argc, char **argv)
00972 {
00973   int c;
00974   AvlTree *tree = avl_create(mycmp, malloc);
00975 
00976   while ((c = getopt(argc, argv, "v")) != -1) {
00977     switch(c) {
00978     case 'v':
00979       verbose = 1;
00980       break;
00981     default:
00982       fprintf(stderr, "Usage: avltest [-v]\n");
00983       exit(1);
00984     }
00985   }
00986 
00987   // specific_test(tree);
00988 
00989   tree_test(tree);
00990 
00991 #if 0
00992   BaseAvlNode *nd1 = make_node(1);
00993   BaseAvlNode *nd2 = make_node(2);
00994   BaseAvlNode *nd3 = make_node(3);
00995   BaseAvlNode *nd4 = make_node(4);
00996   BaseAvlNode *nd5 = make_node(5);
00997   BaseAvlNode *nd6 = make_node(6);
00998   BaseAvlNode *nd7 = make_node(7);
00999   BaseAvlNode *nd8 = make_node(8);
01000 
01001   avl_dump(stdout, tree, myshow);
01002 
01003   fprintf(stdout, "Insert nd1\n");
01004   avl_insert(tree, nd1);
01005   avl_dump(stdout, tree, myshow);
01006 
01007   fprintf(stdout, "Insert nd2\n");
01008   avl_insert(tree, nd2);
01009   avl_dump(stdout, tree, myshow);
01010 
01011   fprintf(stdout, "Remove nd2\n");
01012   avl_remove(tree, nd2);
01013   avl_dump(stdout, tree, myshow);
01014 
01015   fprintf(stdout, "Re-Insert nd2\n");
01016   avl_insert(tree, nd2);
01017   avl_dump(stdout, tree, myshow);
01018 
01019   fprintf(stdout, "Remove nd1\n");
01020   avl_remove(tree, nd1);
01021   avl_dump(stdout, tree, myshow);
01022 
01023   fprintf(stdout, "Re-Insert nd1\n");
01024   avl_insert(tree, nd1);
01025   avl_dump(stdout, tree, myshow);
01026 
01027   fprintf(stdout, "Insert nd5\n");
01028   avl_insert(tree, nd5);
01029   avl_dump(stdout, tree, myshow);
01030 
01031   fprintf(stdout, "Insert nd3\n");
01032   avl_insert(tree, nd3);
01033   avl_dump(stdout, tree, myshow);
01034 
01035   fprintf(stdout, "Remove nd3\n");
01036   avl_remove(tree, nd3);
01037   avl_dump(stdout, tree, myshow);
01038 
01039   fprintf(stdout, "Re-Insert nd3\n");
01040   avl_insert(tree, nd3);
01041   avl_dump(stdout, tree, myshow);
01042 
01043   fprintf(stdout, "Insert nd4\n");
01044   avl_insert(tree, nd4);
01045   avl_dump(stdout, tree, myshow);
01046 
01047   fprintf(stdout, "Insert nd6\n");
01048   avl_insert(tree, nd6);
01049   avl_dump(stdout, tree, myshow);
01050 
01051   fprintf(stdout, "Insert nd7\n");
01052   avl_insert(tree, nd7);
01053   avl_dump(stdout, tree, myshow);
01054 
01055   fprintf(stdout, "Remove nd6\n");
01056   avl_remove(tree, nd6);
01057   avl_dump(stdout, tree, myshow);
01058 
01059   fprintf(stdout, "Remove nd5\n");
01060   avl_remove(tree, nd5);
01061   avl_dump(stdout, tree, myshow);
01062 
01063   fprintf(stdout, "Insert nd5\n");
01064   avl_insert(tree, nd5);
01065   avl_dump(stdout, tree, myshow);
01066 
01067   fprintf(stdout, "Insert nd6\n");
01068   avl_insert(tree, nd6);
01069   avl_dump(stdout, tree, myshow);
01070 
01071   fprintf(stdout, "Insert nd8\n");
01072   avl_insert(tree, nd8);
01073   avl_dump(stdout, tree, myshow);
01074 #endif
01075 
01076   exit(0);
01077 }
01078 #endif

Generated on Sun Apr 23 22:42:34 2006 for OpenCM by  doxygen 1.4.6