lib/rbTree.c

Go to the documentation of this file.
00001 /* rbTree - rbTreeRed-rbTreeBlack Tree - a type of binary tree which 
00002  * automatically keeps relatively balanced during
00003  * inserts and deletions.
00004  *   original author: Shane Saunders
00005  *   adapted into local conventions: Jim Kent
00006  */
00007 
00008 #include "common.h"
00009 #include "localmem.h"
00010 #include "rbTree.h"
00011 
00012 static char const rcsid[] = "$Id: rbTree.c,v 1.10 2007/02/24 15:59:29 kent Exp $";
00013 
00014 
00015 static struct rbTreeNode *restructure(struct rbTree *t, int tos, 
00016         struct rbTreeNode *x, struct rbTreeNode *y, struct rbTreeNode *z)
00017 /* General restructuring function - checks for all
00018  * restructuring cases.  Call when insert has messed up tree.
00019  * Sadly delete has to do even more work. */
00020 {
00021 struct rbTreeNode *parent, *midNode;
00022 
00023 if(y == x->left) 
00024     {
00025     if(z == y->left) 
00026         {  /* in-order:  z, y, x */
00027         midNode = y;
00028         y->left = z;
00029         x->left = y->right;
00030         y->right = x;
00031         }
00032     else 
00033         {  /* in-order:  y, z, x */
00034         midNode = z;
00035         y->right = z->left;
00036         z->left = y;
00037         x->left = z->right;
00038         z->right = x;
00039         }
00040     }
00041 else 
00042     {
00043     if(z == y->left) 
00044         {  /* in-order:  x, z, y */
00045         midNode = z;
00046         x->right = z->left;
00047         z->left = x;
00048         y->left = z->right;
00049         z->right = y;
00050         }
00051     else 
00052         {  /* in-order:  x, y, z */
00053         midNode = y;
00054         x->right = y->left;
00055         y->left = x;
00056         y->right = z;
00057         }
00058     }
00059 if(tos != 0) 
00060     {
00061     parent = t->stack[tos-1];
00062     if(x == parent->left) 
00063         parent->left = midNode;
00064     else 
00065         parent->right = midNode;
00066     }
00067 else 
00068     t->root = midNode;
00069 
00070 return midNode;
00071 }
00072 
00073 struct rbTree *rbTreeNewDetailed(int (*compare)(void *, void *), struct lm *lm, 
00074         struct rbTreeNode *stack[128])
00075 /* Allocate rbTree on an existing local memory & stack.  This is for cases
00076  * where you want a lot of trees, and don't want the overhead for each one. 
00077  * Note, to clean these up, just do freez(&rbTree) rather than rbFreeTree(&rbTree). */
00078 {
00079 struct rbTree *t;
00080 AllocVar(t);
00081 t->root = NULL;
00082 t->compare = compare;
00083 t->lm = lm;
00084 t->stack = stack;       
00085 t->n = 0;
00086 return t;
00087 }
00088 
00089 struct rbTree *rbTreeNew(int (*compare)(void *, void *))
00090 /* rbTreeNew() - Allocates space for a red-black tree and returns a pointer
00091  * to it.  The function compare compares they keys of two items, and returns a
00092  * negative, zero, or positive integer depending on whether the first item is
00093  * less than, equal to, or greater than the second.  */
00094 {
00095 /* The stack keeps us from having to keep explicit
00096  * parent, grandparent, greatgrandparent variables.
00097  * It needs to be big enough for the maximum depth
00098  * of tree.  Since the whole point of rb trees is
00099  * that they are self-balancing, this is not all
00100  * that deep, just 2*log2(N).  Therefore a stack of
00101  * 128 is good for up to 2^64 items in stack, which
00102  * should keep us for the next couple of decades... */
00103 struct lm *lm = lmInit(0);
00104 struct rbTreeNode **stack = lmAlloc(lm, 128 * sizeof(stack[0]));        
00105 return rbTreeNewDetailed(compare, lm, stack);
00106 }
00107 
00108 
00109 void rbTreeFree(struct rbTree **pTree)
00110 /* rbTreeFree() - Frees space used by the red-black tree pointed to by t. */
00111 {
00112 struct rbTree *tree = *pTree;
00113 if (tree != NULL)
00114     {
00115     lmCleanup(&tree->lm);
00116     freez(pTree);
00117     }
00118 }
00119 
00120 
00121 void *rbTreeAdd(struct rbTree *t, void *item)
00122 /* rbTreeAdd() - Inserts an item into the red-black tree pointed to by t,
00123  * according the the value its key.  The key of an item in the red-black
00124  * tree must be unique among items in the tree.  If an item with the same key
00125  * already exists in the tree, a pointer to that item is returned.  Otherwise,
00126  * NULL is returned, indicating insertion was successful.
00127  */
00128 {
00129 struct rbTreeNode *x, *p, *q, *m, **attachX;
00130 int (* compare)(void *, void *);
00131 int cmpResult;
00132 rbTreeColor col;
00133 struct rbTreeNode **stack = NULL;
00134 int tos;
00135 
00136 tos = 0;    
00137 if((p = t->root) != NULL) 
00138     {
00139     compare = t->compare;
00140     stack = t->stack;
00141 
00142     /* Repeatedly explore either the left branch or the right branch
00143      * depending on the value of the key, until an empty branch is chosen.
00144      */
00145     for(;;) 
00146         {
00147         stack[tos++] = p;
00148         cmpResult = compare(item, p->item);
00149         if(cmpResult < 0) 
00150             {
00151             p = p->left;
00152             if(!p) 
00153                 {
00154                 p = stack[--tos];
00155                 attachX = &p->left;
00156                 break;
00157                 }
00158             }
00159         else if(cmpResult > 0) 
00160             {
00161             p = p->right;
00162             if(!p) 
00163                 {
00164                 p = stack[--tos];
00165                 attachX = &p->right;
00166                 break;
00167                 }
00168             }
00169         else 
00170             {
00171             return p->item;
00172             }
00173         }
00174     col = rbTreeRed;
00175     }
00176 else 
00177     {
00178     attachX = &t->root;
00179     col = rbTreeBlack;
00180     }
00181 
00182 /* Allocate new node and place it in tree. */
00183 if ((x = t->freeList) != NULL)
00184     t->freeList = x->right;
00185 else
00186     lmAllocVar(t->lm, x);
00187 x->left = x->right = NULL;
00188 x->item = item;
00189 x->color = col;
00190 *attachX = x;
00191 t->n++;
00192 
00193 /* Restructuring or recolouring will be needed if node x and its parent, p,
00194  * are both red.
00195  */
00196 if(tos > 0) 
00197     {
00198     while(p->color == rbTreeRed) 
00199         {  /* Double red problem. */
00200 
00201         /* Obtain a pointer to p's parent, m, and sibling, q. */
00202         m = stack[--tos];
00203         q = p == m->left ? m->right : m->left;
00204         
00205         /* Determine whether restructuring or recolouring is needed. */
00206         if(!q || q->color == rbTreeBlack) 
00207             {
00208             /* Sibling is black.  ==>  Perform restructuring. */
00209             
00210             /* Restructure according to the left to right order, of nodes
00211              * m, p, and x.
00212              */
00213             m = restructure(t, tos, m, p, x);
00214             m->color = rbTreeBlack;
00215             m->left->color = m->right->color = rbTreeRed;
00216 
00217             /* Restructuring eliminates the double red problem. */
00218             break;
00219             }
00220         /* else just need to flip color */
00221         
00222         /* Sibling is also red.  ==>  Perform recolouring. */
00223         p->color = rbTreeBlack;
00224         q->color = rbTreeBlack;
00225 
00226         if(tos == 0) break;  /* The root node always remains black. */
00227             
00228         m->color = rbTreeRed;
00229 
00230         /* Continue, checking colouring higher up. */
00231         x = m;
00232         p = stack[--tos];
00233         }
00234     }
00235 
00236 return NULL;
00237 }
00238 
00239 
00240 void *rbTreeFind(struct rbTree *t, void *item)
00241 /* rbTreeFind() - Find an item in the red-black tree with the same key as the
00242  * item pointed to by `item'.  Returns a pointer to the item found, or NULL
00243  * if no item was found.
00244  */
00245 {
00246 struct rbTreeNode *p, *nextP;
00247 int (*compare)(void *, void *) = t->compare;
00248 int cmpResult;
00249     
00250 /* Repeatedly explore either the left or right branch, depending on the
00251  * value of the key, until the correct item is found.  */
00252 for (p = t->root; p != NULL; p = nextP)
00253     {
00254     cmpResult = compare(item, p->item);
00255     if(cmpResult < 0) 
00256         nextP = p->left;
00257     else if(cmpResult > 0) 
00258         nextP = p->right;
00259     else 
00260         return p->item;
00261     }
00262 return NULL;
00263 }
00264 
00265 
00266 void *rbTreeRemove(struct rbTree *t, void *item)
00267 /* rbTreeRemove() - Delete an item in the red-black tree with the same key as
00268  * the item pointed to by `item'.  Returns a pointer to the deleted item,
00269  * and NULL if no item was found.
00270  */
00271 {
00272 struct rbTreeNode *p, *r, *x, *y, *z, *b, *newY;
00273 struct rbTreeNode *m;
00274 rbTreeColor removeCol;
00275 void *returnItem;
00276 int (* compare)(void *, void *);
00277 int cmpResult;
00278 struct rbTreeNode **stack;
00279 int i, tos;
00280 
00281 
00282 /* Attempt to locate the item to be deleted. */
00283 if((p = t->root)) 
00284     {
00285     compare = t->compare;
00286     stack = t->stack;
00287     tos = 0;
00288     
00289     for(;;) 
00290         {
00291         stack[tos++] = p;
00292         cmpResult = compare(item, p->item);
00293         if(cmpResult < 0) 
00294             p = p->left;
00295         else if(cmpResult > 0) 
00296             p = p->right;
00297         else 
00298             /* Item found. */
00299             break;
00300         if(!p) return NULL;
00301         }
00302     }
00303 else 
00304     return NULL;
00305 
00306 /* p points to the node to be deleted, and is currently on the top of the
00307  * stack.
00308  */
00309 if(!p->left) 
00310     {
00311     tos--;  /* Adjust tos to remove p. */
00312     /* Right child replaces p. */
00313     if(tos == 0) 
00314         {
00315         r = t->root = p->right;
00316         x = y = NULL;
00317         }
00318     else 
00319         {
00320         x = stack[--tos];
00321         if(p == x->left) 
00322             {
00323             r = x->left = p->right;
00324             y = x->right;
00325             }
00326         else 
00327             {
00328             r = x->right = p->right;
00329             y = x->left;
00330             }
00331         }
00332     removeCol = p->color;
00333     }
00334 else if(!p->right) 
00335     {
00336     tos--;  /* Adjust tos to remove p. */
00337     /* Left child replaces p. */
00338     if(tos == 0) 
00339         {
00340         r = t->root = p->left;
00341         x = y = NULL;
00342         }
00343     else 
00344         {
00345         x = stack[--tos];
00346         if(p == x->left) 
00347             {
00348             r = x->left = p->left;
00349             y = x->right;
00350             }
00351         else 
00352             {
00353             r = x->right = p->left;
00354             y = x->left;
00355             }
00356         }
00357     removeCol = p->color;
00358     }
00359 else 
00360     {
00361     /* Save p's stack position. */
00362     i = tos-1;
00363     
00364     /* Minimum child, m, in the right subtree replaces p. */
00365     m = p->right;
00366     do 
00367         {
00368         stack[tos++] = m;
00369         m = m->left;
00370         } while(m);
00371     m = stack[--tos];
00372 
00373     /* Update either the left or right child pointers of p's parent. */
00374     if(i == 0) 
00375         {
00376         t->root = m;
00377         }
00378     else 
00379         {
00380         x = stack[i-1];  /* p's parent. */
00381         if(p == x->left) 
00382             {
00383             x->left = m;
00384             }
00385         else 
00386             {
00387             x->right = m;
00388             }
00389         }
00390     
00391     /* Update the tree part m is removed from, and assign m the child
00392      * pointers of p (only if m is not the right child of p).
00393      */
00394     stack[i] = m;  /* Node m replaces node p on the stack. */
00395     x = stack[--tos];
00396     r = m->right;
00397     if(tos != i) 
00398         {  /* x is equal to the parent of m. */
00399         y = x->right;
00400         x->left = r;
00401         m->right = p->right;
00402         }
00403     else 
00404         { /* m was the right child of p, and x is equal to m. */
00405         y = p->left;
00406         }
00407     m->left = p->left;
00408 
00409     /* We treat node m as the node which has been removed. */
00410     removeCol = m->color;
00411     m->color = p->color;
00412     }
00413 
00414 /* Get return value and reuse the space used by node p. */
00415 returnItem = p->item;
00416 p->right = t->freeList;
00417 t->freeList = p;
00418 
00419 t->n--;
00420 
00421 /* The pointers x, y, and r point to nodes which may be involved in
00422  * restructuring and recolouring.
00423  *  x - the parent of the removed node.
00424  *  y - the sibling of the removed node.
00425  *  r - the node which replaced the removed node.
00426  * From the above code, the next entry off the stack will be the parent of
00427  * node x.
00428  */
00429 
00430 /* The number of black nodes on paths to all external nodes (NULL child
00431  * pointers) must remain the same for all paths.  Restructuring or
00432  * recolouring of nodes may be necessary to enforce this.
00433  */
00434 if(removeCol == rbTreeBlack) 
00435     {
00436     /* Removal of a black node requires some adjustment. */
00437     
00438     if(!r || r->color == rbTreeBlack) 
00439         {
00440         /* A black node replaced the deleted black node.  Note that
00441          * external nodes (NULL child pointers) are always black, so
00442          * if r is NULL it is treated as a black node.
00443          */
00444 
00445         /* This causes a double-black problem, since node r would need to
00446          * be coloured double-black in order for the black color on
00447          * paths through r to remain the same as for other paths.
00448          */
00449 
00450         /* If r is the root node, the double-black color is not necessary
00451          * to maintain the color balance.  Otherwise, some adjustment of
00452          * nearby nodes is needed in order to eliminate the double-black
00453          * problem.  NOTE:  x points to the parent of r.
00454          */
00455         if(x) for(;;) 
00456             {
00457 
00458             /* There are three adjustment cases:
00459              *  1.  r's sibling, y, is black and has a red child, z.
00460              *  2.  r's sibling, y, is black and has two black children.
00461              *  3.  r's sibling, y, is red.
00462              */
00463             if(y->color == rbTreeBlack) 
00464                 {
00465 
00466                 /* Note the conditional evaluation for assigning z. */
00467                 if(((z = y->left) && z->color == rbTreeRed) ||
00468                    ((z = y->right) && z->color == rbTreeRed)) 
00469                        {                    
00470                     /* Case 1:  perform a restructuring of nodes x, y, and
00471                      * z.
00472                      */
00473                     
00474                     b = restructure(t, tos, x, y, z);
00475                     b->color = x->color;
00476                     b->left->color = b->right->color = rbTreeBlack;
00477                     
00478                     break;
00479                     }
00480                 else 
00481                     {
00482                     /* Case 2:  recolour node y red. */
00483                     
00484                     y->color = rbTreeRed;
00485                     
00486                     if(x->color == rbTreeRed) 
00487                         {
00488                         x->color = rbTreeBlack;
00489                         break;
00490                         }
00491                     /* else */
00492 
00493                     if(tos == 0) break;  /* Root level reached. */
00494                     /* else */
00495                     
00496                     r = x;
00497                     x = stack[--tos];  /* x <- parent of x. */
00498                     y = x->left == r ? x->right : x->left;
00499                     }
00500                 }
00501             else 
00502                 {
00503                 /* Case 3:  Restructure nodes x, y, and z, where:
00504                  *  - If node y is the left child of x, then z is the left
00505                  *    child of y.  Otherwise z is the right child of y.
00506                  */
00507                 if(x->left == y) 
00508                     {
00509                     newY = y->right;
00510                     z = y->left;
00511                     }
00512                 else 
00513                     {
00514                     newY = y->left;
00515                     z = y->right;
00516                     }
00517                 
00518                 restructure(t, tos, x, y, z);
00519                 y->color = rbTreeBlack;
00520                 x->color = rbTreeRed;
00521 
00522                 /* Since x has moved down a place in the tree, and y is the
00523                  * new the parent of x, the stack must be adjusted so that
00524                  * the parent of x is correctly identified in the next call
00525                  * to restructure().
00526                  */
00527                 stack[tos++] = y;
00528 
00529                 /* After restructuring, node r has a black sibling, newY,
00530                  * so either case 1 or case 2 applies.  If case 2 applies
00531                  * the double-black problem does not reappear.
00532                  */
00533                 y = newY;
00534                 
00535                 /* Note the conditional evaluation for assigning z. */
00536                 if(((z = y->left) && z->color == rbTreeRed) ||
00537                    ((z = y->right) && z->color == rbTreeRed)) 
00538                    {                
00539                     /* Case 1:  perform a restructuring of nodes x, y, and
00540                      * z.
00541                      */
00542                     
00543                     b = restructure(t, tos, x, y, z);
00544                     b->color = rbTreeRed;  /* Since node x was red. */
00545                     b->left->color = b->right->color = rbTreeBlack;
00546                     }
00547                 else 
00548                     {
00549                     /* Case 2:  recolour node y red. */
00550 
00551                     /* Note that node y is black and node x is red. */
00552                     
00553                     y->color = rbTreeRed;
00554                     x->color = rbTreeBlack;
00555                     }
00556 
00557                 break;
00558                 }
00559             }
00560         }
00561     else 
00562         {
00563         /* A red node replaced the deleted black node. */
00564 
00565         /* In this case we can simply color the red node black. */
00566         r->color = rbTreeBlack;
00567         }
00568     }
00569 return returnItem;
00570 }
00571 
00572 /* Some variables to help recursively dump tree. */
00573 static int dumpLevel;   /* Indentation level. */
00574 static FILE *dumpFile;  /* Output file */
00575 static void (*dumpIt)(void *item, FILE *f);  /* Item dumper. */
00576 
00577 static void rTreeDump(struct rbTreeNode *n)
00578 /* Recursively dump. */
00579 {
00580 if (n == NULL)
00581     return;
00582 spaceOut(dumpFile, ++dumpLevel * 3);
00583 fprintf(dumpFile, "%c ", (n->color ==  rbTreeRed ? 'r' : 'b'));
00584 dumpIt(n->item, dumpFile);
00585 fprintf(dumpFile, "\n");
00586 rTreeDump(n->left);
00587 rTreeDump(n->right);
00588 --dumpLevel;
00589 }
00590 
00591 void rbTreeDump(struct rbTree *tree, FILE *f, 
00592         void (*dumpItem)(void *item, FILE *f))
00593 /* Dump out rb tree to file, mostly for debugging. */
00594 {
00595 dumpFile = f;
00596 dumpLevel = 0;
00597 dumpIt = dumpItem;
00598 fprintf(f, "rbTreeDump\n");
00599 rTreeDump(tree->root);
00600 }
00601 
00602 
00603 
00604 /* Variables to help recursively traverse tree. */
00605 static void (*doIt)(void *item);
00606 static void *minIt, *maxIt;
00607 static int (*compareIt)(void *, void *);
00608 
00609 static void rTreeTraverseRange(struct rbTreeNode *n)
00610 /* Recursively traverse tree in range applying doIt. */
00611 {
00612 if (n != NULL)
00613    {
00614    int minCmp = compareIt(n->item, minIt);
00615    int maxCmp = compareIt(n->item, maxIt);
00616    if (minCmp >= 0)
00617        rTreeTraverseRange(n->left);
00618    if (minCmp >= 0 && maxCmp <= 0)
00619        doIt(n->item);
00620    if (maxCmp <= 0)
00621        rTreeTraverseRange(n->right);
00622    }
00623 }
00624 
00625 static void rTreeTraverse(struct rbTreeNode *n)
00626 /* Recursively traverse full tree applying doIt. */
00627 {
00628 if (n != NULL)
00629     {
00630     rTreeTraverse(n->left);
00631     doIt(n->item);
00632     rTreeTraverse(n->right);
00633     }
00634 }
00635 
00636 void rbTreeTraverseRange(struct rbTree *tree, void *minItem, void *maxItem,
00637         void (*doItem)(void *item))
00638 /* Apply doItem function to all items in tree such that
00639  * minItem <= item <= maxItem */
00640 {
00641 doIt = doItem;
00642 minIt = minItem;
00643 maxIt = maxItem;
00644 compareIt = tree->compare;
00645 rTreeTraverseRange(tree->root);
00646 }
00647 
00648 void rbTreeTraverse(struct rbTree *tree, void (*doItem)(void *item))
00649 /* Apply doItem function to all items in tree */
00650 {
00651 doIt = doItem;
00652 compareIt = tree->compare;
00653 rTreeTraverse(tree->root);
00654 }
00655 
00656 struct slRef *itList;  /* List of items that rbTreeItemsInRange returns. */
00657 
00658 static void addRef(void *item)
00659 /* Add item it itList. */
00660 {
00661 refAdd(&itList, item);
00662 }
00663 
00664 struct slRef *rbTreeItemsInRange(struct rbTree *tree, void *minItem, void *maxItem)
00665 /* Return a sorted list of references to items in tree between range.
00666  * slFreeList this list when done. */
00667 {
00668 itList = NULL;
00669 rbTreeTraverseRange(tree, minItem, maxItem, addRef);
00670 slReverse(&itList);
00671 return itList;
00672 }
00673 
00674 struct slRef *rbTreeItems(struct rbTree *tree)
00675 /* Return sorted list of items.  slFreeList this when done.*/
00676 {
00677 itList = NULL;
00678 rbTreeTraverse(tree, addRef);
00679 slReverse(&itList);
00680 return itList;
00681 }
00682 
00683 int rbTreeCmpString(void *a, void *b)
00684 /* Set up rbTree so as to work on strings. */
00685 {
00686 return strcmp(a, b);
00687 }
00688 
00689 int rbTreeCmpWord(void *a, void *b)     
00690 /* Set up rbTree so as to work on case-insensitive strings. */
00691 {
00692 return differentWord(a,b);
00693 }

Generated on Tue Dec 25 18:39:31 2007 for blat by  doxygen 1.5.2