void * insertelt_rbtree_sub ( RBTREE tree, RBNODE node, int (*compfun)(const void *,const void *), void * key, void * value){ assert(NULL!=node); assert(NULL!=compfun); assert(NULL!=key); assert(NULL!=value); int comparison = compfun(key,node->key); if ( comparison == 0){ /* key already in tree. Balancing not affected */ void * oldvalue = node->value; node->value = value; return oldvalue; } RBNODE * childnodep = NULL; if ( comparison<0 ){ childnodep = &(node->left); } else if ( comparison>0 ){ childnodep = &(node->right); } /* Continue down tree */ if (NULL != *childnodep){return insertelt_rbtree_sub(tree,*childnodep,compfun,key,value);} *childnodep = create_rbnode(red); (*childnodep)->key = tree->copykey(key); (*childnodep)->value = value; (*childnodep)->parent = node; balance_rbtree (*childnodep,tree); return NULL; }
void rb_insert(rbtree* tree, int data) { rbnode* pn = rb_search(tree, data); rbnode* nn = create_rbnode(data); if (!pn) { tree->root = nn; nn->color = BLACK; return; } else if (data == pn->data) { return; } else if (data < pn->data) { pn->left = nn; nn->parent = pn; } else if (data > pn->data) { pn->right = nn; nn->parent = pn; } while (pn && pn->color == RED) { if (IS_LEFT(pn)) { rbnode* uncle = pn->parent->right; if (uncle && uncle->color == RED) { pn->color = uncle->color = BLACK; pn->parent->color = RED; nn = pn->parent; pn = nn->parent; continue; } if (IS_RIGHT(nn)) { LEFT_ROTATE(tree, pn); SWAP(nn, pn, rbnode*); } RIGHT_ROTATE(tree, pn->parent); pn->color = BLACK; pn->right->color = RED; break; } else { rbnode* uncle = pn->parent->left; if (uncle && uncle->color == RED) { pn->color = uncle->color = BLACK; pn->parent->color = RED; nn = pn->parent; pn = nn->parent; continue; } if (IS_LEFT(nn)) { RIGHT_ROTATE(tree, pn); SWAP(nn, pn, rbnode*); } LEFT_ROTATE(tree, pn->parent); pn->color = BLACK; pn->left->color = RED; break; } } // nn is root if (!pn) nn->color = BLACK; }
void * insertelt_rbtree ( RBTREE tree, void * key, void * value){ assert(NULL!=tree); assert(NULL!=key); assert(NULL!=value); if ( NULL==tree->root){ /* Tree empty, root must be black */ tree->root = create_rbnode (black); tree->root->key = tree->copykey(key); tree->root->value = value; tree->root->parent = NULL; return NULL; } /* Find location to add */ return insertelt_rbtree_sub (tree, tree->root, tree->compfun, key, value); }
RBNODE copy_rbnode_sub ( const RBNODE node, void * (*copykey)(const void *), void * (*copyvalue)(const void *) ){ assert(NULL!=node); assert(NULL!=copykey); RBNODE newnode = create_rbnode(black); newnode->colour = node->colour; newnode->key = copykey(node->key); newnode->value = (NULL!=copyvalue)?copyvalue(node->value):node->value; if (NULL!=node->left){ newnode->left = copy_rbnode_sub(node->left,copykey,copyvalue); newnode->left->parent = newnode; } if (NULL!=node->right){ newnode->right = copy_rbnode_sub(node->right,copykey,copyvalue); newnode->right->parent = newnode; } return newnode; }
/* Need to decide what to do about memory for keys. * Possible memory leak at moment. */ void * removeelt_rbtree (RBTREE tree, const void * key){ RBNODE phantom = NULL; void * retval = NULL; assert(NULL!=tree); assert(NULL!=key); RBNODE delnode = search_rbtree(tree,key); if (NULL==delnode){ return retval;} /* Nothing to delete */ retval = delnode->value; tree->freekey(delnode->key); /* Node has two non-null children. Transform so not case */ if (NULL!=delnode->right && NULL!=delnode->left){ RBNODE leftmost = minnode_rbtree_sub(delnode->right); delnode->key = leftmost->key; delnode->value = leftmost->value; delnode = leftmost; } /* delnode now has at most one child */ enum rbcolour delcol = delnode->colour; RBNODE child = (NULL==delnode->right)?delnode->left:delnode->right; if ( NULL==child){ child = create_rbnode(black); /* "Phantom node" */ phantom = child; } /* Replace node with child */ if (NULL!=delnode->parent){ if (delnode->parent->left==delnode) delnode->parent->left = child; else if (delnode->parent->right==delnode) delnode->parent->right = child; else abort(); } else { tree->root = child; } child->parent = delnode->parent; free(delnode); if(red==delcol){ goto remove_end;} /* Deleted node was black */ if (red==colour_rbnode(child)){ child->colour = black; goto remove_end;} case1: /* Case 1 */ if ( NULL==child->parent){ /* New root */ tree->root = child; goto remove_end; } /* Case 2 */ RBNODE sibling = sibling_rbnode(child); if ( red==colour_rbnode(sibling)){ child->parent->colour = red; sibling->colour = black; if ( child == child->parent->left) rotate_left_rbtree (child->parent,tree); else rotate_right_rbtree(child->parent,tree); } sibling = sibling_rbnode(child); assert(sibling->colour==black); /* Case 3 */ if ( black== child->parent->colour && black==colour_rbnode(sibling->left) && black==colour_rbnode(sibling->right)){ sibling->colour = red; child = child->parent; goto case1; } assert(sibling->colour==black); /* Case 4 */ if ( red == child->parent->colour && black==colour_rbnode(sibling->left) && black==colour_rbnode(sibling->right)){ sibling->colour = red; child->parent->colour = black; goto remove_end; } assert(sibling->colour == black); /* Case 5 */ if ( child==child->parent->left && red==colour_rbnode(sibling->left) && black==colour_rbnode(sibling->right)){ sibling->colour = red; sibling->left->colour = black; rotate_right_rbtree(sibling,tree); } else if ( child==child->parent->right && black==colour_rbnode(sibling->left) && red==colour_rbnode(sibling->right)){ sibling->colour = red; sibling->right->colour = black; rotate_left_rbtree(sibling,tree); } sibling = sibling_rbnode(child); /* Case 6 */ sibling->colour = child->parent->colour; child->parent->colour = black; if ( child == child->parent->left){ sibling->right->colour = black; rotate_left_rbtree(child->parent,tree); } else { sibling->left->colour = black; rotate_right_rbtree(child->parent,tree); } remove_end: /* Delelte phantom node */ if ( phantom ){ if ( NULL!=phantom->parent){ if (phantom->parent->left == phantom) phantom->parent->left = NULL; else if (phantom->parent->right == phantom) phantom->parent->right = NULL; else abort(); } if(tree->root==phantom){tree->root = NULL;} free(phantom); } return retval; }