void make_balance_after_insert(ptr_rbnode node) { //case 1 : root node if (node->parent == NULL) { node->color = BLACK; return; } //case 2 : parent is black if (node->parent->color == BLACK) { return; //nothing to do } //now it is guaranteed that node has grandparent //case 3 : p and u = red, g = black ptr_rbnode g = get_grandparent(node), u = get_uncle(node), p = node->parent; assert(g); if (p->color == RED && u->color == RED && g->color == BLACK) { p->color = BLACK; u->color = BLACK; g->color = RED; make_balance_after_insert(g); /* this recursive operation will take O(log N) in worst case and O(1) in average case because the time complexity distribution would have a form of geometric distribution. */ return; } //case 4,5 : p = red, u = black, g = black; -> guaranteed //if node, p and g is not on a line, rotate //case 4 would be changed into case 5 assert(p->color == RED && u->color == BLACK && g->color == BLACK); if (g->left == p && p->right == node) { rotate_left(p); node = node->left; //for case 5 g = get_grandparent(node), u = get_uncle(node), p = node->parent; } else if (g->right == p && p->left == node) { rotate_right(p); // for case 5 g = get_grandparent(node), u = get_uncle(node), p = node->parent; node = node->right; } g = get_grandparent(node), u = get_uncle(node), p = node->parent; //case 5 assert((p->left == node && g->left == p) || (p->right == node && g->right == p)); p->color = BLACK; g->color = RED; if (p->left == node) { rotate_right(g); } else { rotate_left(g); } }
/* W. 2+3) Parent of node must be black, otherwise recolor and flush */ static void insert_check_2 (DLRBT_Tree *tree, DLRBT_Node *node) { /* if the parent is not black, we need to change that... */ if (node && node->parent && node->parent->tree_col) { DLRBT_Node *unc= get_uncle(node); /* if uncle and parent are both red, need to change them to black and make * the parent black in order to satisfy the criteria of each node having the * same number of black nodes to its leaves */ if (unc && unc->tree_col) { DLRBT_Node *gp= get_grandparent(node); /* make the n-1 generation nodes black */ node->parent->tree_col= unc->tree_col= DLRBT_BLACK; /* - make the grandparent red, so that we maintain alternating red/black property * (it must exist, so no need to check for NULL here), * - as the grandparent may now cause inconsistencies with the rest of the tree, * we must flush up the tree and perform checks/rebalancing/repainting, using the * grandparent as the node of interest */ gp->tree_col= DLRBT_RED; insert_check_1(tree, gp); } else { /* we've got an unbalanced branch going down the grandparent to the parent, * so need to perform some rotations to re-balance the tree */ insert_check_3(tree, node); } } }
/* W. 4+5) Perform rotation on sub-tree containing the 'new' node, then do any */ static void insert_check_3(DLRBT_Tree *tree, DLRBT_Node *node) { DLRBT_Node *gp = get_grandparent(node); /* check that grandparent and node->parent exist * (jut in case... really shouldn't happen on a good tree) */ if (node && node->parent && gp) { /* a left rotation will switch the roles of node and its parent, assuming that * the parent is the left child of the grandparent... otherwise, rotation direction * should be swapped */ if ((node == node->parent->right) && (node->parent == gp->left)) { rotate_left(tree, node); node = node->left; } else if ((node == node->parent->left) && (node->parent == gp->right)) { rotate_right(tree, node); node = node->right; } /* fix old parent's color-tagging, and perform rotation on the old parent in the * opposite direction if needed for the current situation * NOTE: in the code above, node pointer is changed to point to the old parent */ if (node) { /* get 'new' grandparent (i.e. grandparent for old-parent (node)) */ gp = get_grandparent(node); /* modify the coloring of the grandparent and parent * so that they still satisfy the constraints */ node->parent->tree_col = DLRBT_BLACK; gp->tree_col = DLRBT_RED; /* if there are several nodes that all form a left chain, do a right rotation to correct * this (or a rotation in the opposite direction if they all form a right chain) */ if ((node == node->parent->left) && (node->parent == gp->left)) { rotate_right(tree, gp); } else { // if ((node == node->parent->right) && (node->parent == gp->right)) rotate_left(tree, gp); } } } }
int main() { srand(time(NULL)); node* tree = create_bst(40); for(uint i = 0; i < 10; ++i) { int elem = rand() % 100 + 1; insert(&tree, elem); } insert(&tree, 1337); display_tree(tree); node* test = search(tree, 1337); printf("Grandparent of 1337 is: %d", get_grandparent(tree, test)->data); return 0; }
/* get the 'uncle' - the sibling of the parent - of the given node */ static DLRBT_Node *get_uncle (DLRBT_Node *node) { DLRBT_Node *gpn= get_grandparent(node); /* return the child of the grandparent which isn't the node's parent */ if (gpn) { if (gpn->left == node->parent) return gpn->right; else return gpn->left; } /* not found */ return NULL; }
ptr_rbnode get_uncle(ptr_rbnode node) { ptr_rbnode g = get_grandparent(node); if (g) { if (g->left == node->parent) { return g->right; } else if (g->right == node->parent) { return g->left; } else { assert(0 && "Tree Collapsed"); } } else return NULL; }