#include "red_black_tree.h" /***********************************************************************/ /* FUNCTION: RBTreeCreate */ /**/ /* INPUTS: All the inputs are names of functions. CompFunc takes to */ /* void pointers to keys and returns 1 if the first arguement is */ /* "greater than" the second. DestFunc takes a pointer to a key and */ /* destroys it in the appropriate manner when the node containing that */ /* key is deleted. InfoDestFunc is similiar to DestFunc except it */ /* recieves a pointer to the info of a node and destroys it. */ /* PrintFunc recieves a pointer to the key of a node and prints it. */ /* PrintInfo recieves a pointer to the info of a node and prints it. */ /* If RBTreePrint is never called the print functions don't have to be */ /* defined and NullFunction can be used. */ /**/ /* OUTPUT: This function returns a pointer to the newly created */ /* red-black tree. */ /**/ /* Modifies Input: none */ /***********************************************************************/ rb_red_blk_tree* RBTreeCreate( int (*CompFunc) (const void*,const void*), void (*DestFunc) (void*), void (*InfoDestFunc) (void*), void (*PrintFunc) (const void*), void (*PrintInfo)(void*)) { rb_red_blk_tree* newTree; rb_red_blk_node* temp; newTree=(rb_red_blk_tree*) SafeMalloc(sizeof(rb_red_blk_tree)); newTree->Compare= CompFunc; newTree->DestroyKey= DestFunc; newTree->PrintKey= PrintFunc; newTree->PrintInfo= PrintInfo; newTree->DestroyInfo= InfoDestFunc; /* see the comment in the rb_red_blk_tree structure in red_black_tree.h */ /* for information on nil and root */ temp=newTree->nil= (rb_red_blk_node*) SafeMalloc(sizeof(rb_red_blk_node)); temp->parent=temp->left=temp->right=temp; temp->red=0; temp->key=0; temp=newTree->root= (rb_red_blk_node*) SafeMalloc(sizeof(rb_red_blk_node)); temp->parent=temp->left=temp->right=newTree->nil; temp->key=0; temp->red=0; return(newTree); } /***********************************************************************/ /* FUNCTION: LeftRotate */ /**/ /* INPUTS: This takes a tree so that it can access the appropriate */ /* root and nil pointers, and the node to rotate on. */ /**/ /* OUTPUT: None */ /**/ /* Modifies Input: tree, x */ /**/ /* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ /* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ /* makes the parent of x be to the left of x, x the parent of */ /* its parent before the rotation and fixes other pointers */ /* accordingly. */ /***********************************************************************/ void LeftRotate(rb_red_blk_tree* tree, rb_red_blk_node* x) { rb_red_blk_node* y; rb_red_blk_node* nil=tree->nil; /* I originally wrote this function to use the sentinel for */ /* nil to avoid checking for nil. However this introduces a */ /* very subtle bug because sometimes this function modifies */ /* the parent pointer of nil. This can be a problem if a */ /* function which calls LeftRotate also uses the nil sentinel */ /* and expects the nil sentinel's parent pointer to be unchanged */ /* after calling this function. For example, when RBDeleteFixUP */ /* calls LeftRotate it expects the parent pointer of nil to be */ /* unchanged. */ y=x->right; x->right=y->left; if (y->left != nil) y->left->parent=x; /* used to use sentinel here */ /* and do an unconditional assignment instead of testing for nil */ y->parent=x->parent; /* instead of checking if x->parent is the root as in the book, we */ /* count on the root sentinel to implicitly take care of this case */ if( x == x->parent->left) { x->parent->left=y; } else { x->parent->right=y; } y->left=x; x->parent=y; #ifdef DEBUG_ASSERT Assert(!tree->nil->red,"nil not red in LeftRotate"); #endif } /***********************************************************************/ /* FUNCTION: RighttRotate */ /**/ /* INPUTS: This takes a tree so that it can access the appropriate */ /* root and nil pointers, and the node to rotate on. */ /**/ /* OUTPUT: None */ /**/ /* Modifies Input?: tree, y */ /**/ /* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ /* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ /* makes the parent of x be to the left of x, x the parent of */ /* its parent before the rotation and fixes other pointers */ /* accordingly. */ /***********************************************************************/ void RightRotate(rb_red_blk_tree* tree, rb_red_blk_node* y) { rb_red_blk_node* x; rb_red_blk_node* nil=tree->nil; /* I originally wrote this function to use the sentinel for */ /* nil to avoid checking for nil. However this introduces a */ /* very subtle bug because sometimes this function modifies */ /* the parent pointer of nil. This can be a problem if a */ /* function which calls LeftRotate also uses the nil sentinel */ /* and expects the nil sentinel's parent pointer to be unchanged */ /* after calling this function. For example, when RBDeleteFixUP */ /* calls LeftRotate it expects the parent pointer of nil to be */ /* unchanged. */ x=y->left; y->left=x->right; if (nil != x->right) x->right->parent=y; /*used to use sentinel here */ /* and do an unconditional assignment instead of testing for nil */ /* instead of checking if x->parent is the root as in the book, we */ /* count on the root sentinel to implicitly take care of this case */ x->parent=y->parent; if( y == y->parent->left) { y->parent->left=x; } else { y->parent->right=x; } x->right=y; y->parent=x; #ifdef DEBUG_ASSERT Assert(!tree->nil->red,"nil not red in RightRotate"); #endif } /***********************************************************************/ /* FUNCTION: TreeInsertHelp */ /**/ /* INPUTS: tree is the tree to insert into and z is the node to insert */ /**/ /* OUTPUT: none */ /**/ /* Modifies Input: tree, z */ /**/ /* EFFECTS: Inserts z into the tree as if it were a regular binary tree */ /* using the algorithm described in _Introduction_To_Algorithms_ */ /* by Cormen et al. This funciton is only intended to be called */ /* by the RBTreeInsert function and not by the user */ /***********************************************************************/ void TreeInsertHelp(rb_red_blk_tree* tree, rb_red_blk_node* z) { /* This function should only be called by InsertRBTree (see above) */ rb_red_blk_node* x; rb_red_blk_node* y; rb_red_blk_node* nil=tree->nil; z->left=z->right=nil; y=tree->root; x=tree->root->left; while( x != nil) { y=x; if (1 == tree->Compare(x->key,z->key)) { /* x.key > z.key */ x=x->left; } else { /* x,key <= z.key */ x=x->right; } } z->parent=y; if ( (y == tree->root) || (1 == tree->Compare(y->key,z->key))) { /* y.key > z.key */ y->left=z; } else { y->right=z; } #ifdef DEBUG_ASSERT Assert(!tree->nil->red,"nil not red in TreeInsertHelp"); #endif } /* Before calling Insert RBTree the node x should have its key set */ /***********************************************************************/ /* FUNCTION: RBTreeInsert */ /**/ /* INPUTS: tree is the red-black tree to insert a node which has a key */ /* pointed to by key and info pointed to by info. */ /**/ /* OUTPUT: This function returns a pointer to the newly inserted node */ /* which is guarunteed to be valid until this node is deleted. */ /* What this means is if another data structure stores this */ /* pointer then the tree does not need to be searched when this */ /* is to be deleted. */ /**/ /* Modifies Input: tree */ /**/ /* EFFECTS: Creates a node node which contains the appropriate key and */ /* info pointers and inserts it into the tree. */ /***********************************************************************/ rb_red_blk_node * RBTreeInsert(rb_red_blk_tree* tree, void* key, void* info) { rb_red_blk_node * y; rb_red_blk_node * x; rb_red_blk_node * newNode; x=(rb_red_blk_node*) SafeMalloc(sizeof(rb_red_blk_node)); x->key=key; x->info=info; TreeInsertHelp(tree,x); newNode=x; x->red=1; while(x->parent->red) { /* use sentinel instead of checking for root */ if (x->parent == x->parent->parent->left) { y=x->parent->parent->right; if (y->red) { x->parent->red=0; y->red=0; x->parent->parent->red=1; x=x->parent->parent; } else { if (x == x->parent->right) { x=x->parent; LeftRotate(tree,x); } x->parent->red=0; x->parent->parent->red=1; RightRotate(tree,x->parent->parent); } } else { /* case for x->parent == x->parent->parent->right */ y=x->parent->parent->left; if (y->red) { x->parent->red=0; y->red=0; x->parent->parent->red=1; x=x->parent->parent; } else { if (x == x->parent->left) { x=x->parent; RightRotate(tree,x); } x->parent->red=0; x->parent->parent->red=1; LeftRotate(tree,x->parent->parent); } } } tree->root->left->red=0; return(newNode); #ifdef DEBUG_ASSERT Assert(!tree->nil->red,"nil not red in RBTreeInsert"); Assert(!tree->root->red,"root not red in RBTreeInsert"); #endif } /***********************************************************************/ /* FUNCTION: TreeSuccessor */ /**/ /* INPUTS: tree is the tree in question, and x is the node we want the */ /* the successor of. */ /**/ /* OUTPUT: This function returns the successor of x or NULL if no */ /* successor exists. */ /**/ /* Modifies Input: none */ /**/ /* Note: uses the algorithm in _Introduction_To_Algorithms_ */ /***********************************************************************/ rb_red_blk_node* TreeSuccessor(rb_red_blk_tree* tree,rb_red_blk_node* x) { rb_red_blk_node* y; rb_red_blk_node* nil=tree->nil; rb_red_blk_node* root=tree->root; if (nil != (y = x->right)) { /* assignment to y is intentional */ while(y->left != nil) { /* returns the minium of the right subtree of x */ y=y->left; } return(y); } else { y=x->parent; while(x == y->right) { /* sentinel used instead of checking for nil */ x=y; y=y->parent; } if (y == root) return(nil); return(y); } } /***********************************************************************/ /* FUNCTION: Treepredecessor */ /**/ /* INPUTS: tree is the tree in question, and x is the node we want the */ /* the predecessor of. */ /**/ /* OUTPUT: This function returns the predecessor of x or NULL if no */ /* predecessor exists. */ /**/ /* Modifies Input: none */ /**/ /* Note: uses the algorithm in _Introduction_To_Algorithms_ */ /***********************************************************************/ rb_red_blk_node* TreePredecessor(rb_red_blk_tree* tree, rb_red_blk_node* x) { rb_red_blk_node* y; rb_red_blk_node* nil=tree->nil; rb_red_blk_node* root=tree->root; if (nil != (y = x->left)) { /* assignment to y is intentional */ while(y->right != nil) { /* returns the maximum of the left subtree of x */ y=y->right; } return(y); } else { y=x->parent; while(x == y->left) { if (y == root) return(nil); x=y; y=y->parent; } return(y); } } /***********************************************************************/ /* FUNCTION: InorderTreePrint */ /**/ /* INPUTS: tree is the tree to print and x is the current inorder node */ /**/ /* OUTPUT: none */ /**/ /* EFFECTS: This function recursively prints the nodes of the tree */ /* inorder using the PrintKey and PrintInfo functions. */ /**/ /* Modifies Input: none */ /**/ /* Note: This function should only be called from RBTreePrint */ /***********************************************************************/ void InorderTreePrint(rb_red_blk_tree* tree, rb_red_blk_node* x) { rb_red_blk_node* nil=tree->nil; rb_red_blk_node* root=tree->root; if (x != tree->nil) { InorderTreePrint(tree,x->left); printf("info="); tree->PrintInfo(x->info); printf(" key="); tree->PrintKey(x->key); printf(" l->key="); if( x->left == nil) printf("NULL"); else tree->PrintKey(x->left->key); printf(" r->key="); if( x->right == nil) printf("NULL"); else tree->PrintKey(x->right->key); printf(" p->key="); if( x->parent == root) printf("NULL"); else tree->PrintKey(x->parent->key); printf(" red=%i\n",x->red); InorderTreePrint(tree,x->right); } } /***********************************************************************/ /* FUNCTION: TreeDestHelper */ /**/ /* INPUTS: tree is the tree to destroy and x is the current node */ /**/ /* OUTPUT: none */ /**/ /* EFFECTS: This function recursively destroys the nodes of the tree */ /* postorder using the DestroyKey and DestroyInfo functions. */ /**/ /* Modifies Input: tree, x */ /**/ /* Note: This function should only be called by RBTreeDestroy */ /***********************************************************************/ void TreeDestHelper(rb_red_blk_tree* tree, rb_red_blk_node* x) { rb_red_blk_node* nil=tree->nil; if (x != nil) { TreeDestHelper(tree,x->left); TreeDestHelper(tree,x->right); tree->DestroyKey(x->key); tree->DestroyInfo(x->info); free(x); } } /***********************************************************************/ /* FUNCTION: RBTreeDestroy */ /**/ /* INPUTS: tree is the tree to destroy */ /**/ /* OUTPUT: none */ /**/ /* EFFECT: Destroys the key and frees memory */ /**/ /* Modifies Input: tree */ /**/ /***********************************************************************/ void RBTreeDestroy(rb_red_blk_tree* tree) { TreeDestHelper(tree,tree->root->left); free(tree->root); free(tree->nil); free(tree); } /***********************************************************************/ /* FUNCTION: RBTreePrint */ /**/ /* INPUTS: tree is the tree to print */ /**/ /* OUTPUT: none */ /**/ /* EFFECT: This function recursively prints the nodes of the tree */ /* inorder using the PrintKey and PrintInfo functions. */ /**/ /* Modifies Input: none */ /**/ /***********************************************************************/ void RBTreePrint(rb_red_blk_tree* tree) { InorderTreePrint(tree,tree->root->left); } /***********************************************************************/ /* FUNCTION: RBExactQuery */ /**/ /* INPUTS: tree is the tree to print and q is a pointer to the key */ /* we are searching for */ /**/ /* OUTPUT: returns the a node with key equal to q. If there are */ /* multiple nodes with key equal to q this function returns */ /* the one highest in the tree */ /**/ /* Modifies Input: none */ /**/ /***********************************************************************/ rb_red_blk_node* RBExactQuery(rb_red_blk_tree* tree, void* q) { rb_red_blk_node* x=tree->root->left; rb_red_blk_node* nil=tree->nil; int compVal; if (x == nil) return(0); compVal=tree->Compare(x->key,(int*) q); while(0 != compVal) {/*assignemnt*/ if (1 == compVal) { /* x->key > q */ x=x->left; } else { x=x->right; } if ( x == nil) return(0); compVal=tree->Compare(x->key,(int*) q); } return(x); } /***********************************************************************/ /* FUNCTION: RBDeleteFixUp */ /**/ /* INPUTS: tree is the tree to fix and x is the child of the spliced */ /* out node in RBTreeDelete. */ /**/ /* OUTPUT: none */ /**/ /* EFFECT: Performs rotations and changes colors to restore red-black */ /* properties after a node is deleted */ /**/ /* Modifies Input: tree, x */ /**/ /* The algorithm from this function is from _Introduction_To_Algorithms_ */ /***********************************************************************/ void RBDeleteFixUp(rb_red_blk_tree* tree, rb_red_blk_node* x) { rb_red_blk_node* root=tree->root->left; rb_red_blk_node* w; while( (!x->red) && (root != x)) { if (x == x->parent->left) { w=x->parent->right; if (w->red) { w->red=0; x->parent->red=1; LeftRotate(tree,x->parent); w=x->parent->right; } if ( (!w->right->red) && (!w->left->red) ) { w->red=1; x=x->parent; } else { if (!w->right->red) { w->left->red=0; w->red=1; RightRotate(tree,w); w=x->parent->right; } w->red=x->parent->red; x->parent->red=0; w->right->red=0; LeftRotate(tree,x->parent); x=root; /* this is to exit while loop */ } } else { /* the code below is has left and right switched from above */ w=x->parent->left; if (w->red) { w->red=0; x->parent->red=1; RightRotate(tree,x->parent); w=x->parent->left; } if ( (!w->right->red) && (!w->left->red) ) { w->red=1; x=x->parent; } else { if (!w->left->red) { w->right->red=0; w->red=1; LeftRotate(tree,w); w=x->parent->left; } w->red=x->parent->red; x->parent->red=0; w->left->red=0; RightRotate(tree,x->parent); x=root; /* this is to exit while loop */ } } } x->red=0; #ifdef DEBUG_ASSERT Assert(!tree->nil->red,"nil not black in RBDeleteFixUp"); #endif } /***********************************************************************/ /* FUNCTION: RBDelete */ /**/ /* INPUTS: tree is the tree to delete node z from */ /**/ /* OUTPUT: none */ /**/ /* EFFECT: Deletes z from tree and frees the key and info of z */ /* using DestoryKey and DestoryInfo. Then calls */ /* RBDeleteFixUp to restore red-black properties */ /**/ /* Modifies Input: tree, z */ /**/ /* The algorithm from this function is from _Introduction_To_Algorithms_ */ /***********************************************************************/ void RBDelete(rb_red_blk_tree* tree, rb_red_blk_node* z){ rb_red_blk_node* y; rb_red_blk_node* x; rb_red_blk_node* nil=tree->nil; rb_red_blk_node* root=tree->root; y= ((z->left == nil) || (z->right == nil)) ? z : TreeSuccessor(tree,z); x= (y->left == nil) ? y->right : y->left; if (root == (x->parent = y->parent)) { /* assignment of y->p to x->p is intentional */ root->left=x; } else { if (y == y->parent->left) { y->parent->left=x; } else { y->parent->right=x; } } if (y != z) { /* y should not be nil in this case */ #ifdef DEBUG_ASSERT Assert( (y!=tree->nil),"y is nil in RBDelete\n"); #endif /* y is the node to splice out and x is its child */ if (!(y->red)) RBDeleteFixUp(tree,x); tree->DestroyKey(z->key); tree->DestroyInfo(z->info); y->left=z->left; y->right=z->right; y->parent=z->parent; y->red=z->red; z->left->parent=z->right->parent=y; if (z == z->parent->left) { z->parent->left=y; } else { z->parent->right=y; } free(z); } else { tree->DestroyKey(y->key); tree->DestroyInfo(y->info); if (!(y->red)) RBDeleteFixUp(tree,x); free(y); } #ifdef DEBUG_ASSERT Assert(!tree->nil->red,"nil not black in RBDelete"); #endif } void* RBExactQueryInfo(rb_red_blk_tree* tree, void* key) { rb_red_blk_node* pNode = NULL; pNode = RBExactQuery(tree, key); if (pNode) return pNode->info; return NULL; } /***********************************************************************/ /* FUNCTION: RBDEnumerate */ /**/ /* INPUTS: tree is the tree to look for keys >= low */ /* and <= high with respect to the Compare function */ /**/ /* OUTPUT: stack containing pointers to the nodes between [low,high] */ /**/ /* Modifies Input: none */ /***********************************************************************/ #ifdef HAS_STACK stk_stack* RBEnumerate(rb_red_blk_tree* tree, void* low, void* high) { stk_stack* enumResultStack; rb_red_blk_node* nil=tree->nil; rb_red_blk_node* x=tree->root->left; rb_red_blk_node* lastBest=nil; enumResultStack=StackCreate(); while(nil != x) { if ( 1 == (tree->Compare(x->key,high)) ) { /* x->key > high */ x=x->left; } else { lastBest=x; x=x->right; } } while ( (lastBest != nil) && (1 != tree->Compare(low,lastBest->key))) { StackPush(enumResultStack,lastBest); lastBest=TreePredecessor(tree,lastBest); } return(enumResultStack); } #endif