avl_node *avl_remove_retrace(avl_node *n){ avl_node *p = n->parent; if(!p){ return n; } if(n == p->left){//+2 cases switch(p->balance){ case -1: p->balance = 0; return avl_remove_retrace(p); case 0://change in height absorbed p->balance = 1; return avl_root(p); }//default: p->balance == 1 return avl_remove_rebalance_l(p); }//otherwise n == p->right switch(p->balance){//-2 cases case 1: p->balance = 0; return avl_remove_retrace(p); case 0://change in height absorbed p->balance = -1; return avl_root(p); }//default: p->balance == -1 return avl_remove_rebalance_r(p); }
avl_node *avl_insert_retrace(avl_node *n){ avl_node *p = n->parent; if(!p){ return n; } if(n == p->right){//+2 cases switch(p->balance){ case -1://height change absorbed p->balance = 0; return avl_root(p); case 0: p->balance = 1; return avl_insert_retrace(p); }//default: p->balance == 1 return avl_insert_rebalance_r(p, n);//height change will be absorbed }//otherwise n == p->left switch(p->balance){//-2 cases case 1://height change absorbed p->balance = 0; return avl_root(p); case 0: p->balance = -1; return avl_insert_retrace(p); }//default: p->balance == -1 return avl_insert_rebalance_l(p, n);//height change will be absorbed }
avl_node *avl_insert_rebalance_l(avl_node *p, avl_node *n){//mirror image of avl_insert_rebalance_r if(n->balance == -1){ avl_rotate_l(p); p->balance = n->balance = 0; return avl_root(n); } avl_rotate_r(n); avl_rotate_l(p); n->balance = -(n->parent->balance == 1); p->balance = +(n->parent->balance == -1);//unary + for symmetry n->parent->balance = 0; return avl_root(n->parent); }
avl_node *avl_insert_rebalance_r(avl_node *p, avl_node *n){ if(n->balance == 1){//right-right case: only one rotation needed avl_rotate_r(p);//note n becomes the parent of p p->balance = n->balance = 0; return avl_root(n); }//otherwise right-left case: two rotations are required and the balance factors have 3 cases avl_rotate_l(n); avl_rotate_r(p);//note p, n->left, n change roles from parent, right child, right-left grandchild to left child, parent, right child n->balance = +(n->parent->balance == -1);//n, now the right child of n->parent, its old left child, has a balance factor of 1 if the child was -1, else 0 p->balance = -(n->parent->balance == 1);//p, now the right child of n->parent, has a balance factor of -1 if n->parent was 1, else 0 n->parent->balance = 0;//if this is still confusing, try drawing out all of the possible trees with root +2 and right child +/-1 with irrelevant subtrees only marked as heights. return avl_root(n->parent);//there are 4 cases and I will try to put them in a pdf somewhere if I can figure out how to draw it on a computer. }
// erase an entry void avl_erase(sb_avl * instance, void * key) { avl_node * v = avl_finder(key, avl_root(instance), instance->cmp_keys); if ( v == NULL ) { return; } avl_delete(instance, v); }
avl_node * avl_find_max(sb_avl * instance) { avl_node * x = avl_root(instance); while (x->right != NULL) { x = x->right; } return x; }
avl_node * avl_find_min(sb_avl * instance) { avl_node * x = avl_root(instance); while (x->left != NULL) { x = x->left; } return x; }
void avl_insert(sb_avl * instance, void * key, void * data) { avl_node * curr_node, * prev_node, * q, * x, * y, * z; // insert into empty AVL tree if (avl_root(instance) == NULL) { instance->root = avl_new_node(key, data); instance->root->height = 1; return; } curr_node = instance->root; prev_node = instance->root; // traverse until NULL, keeping track of the parent while ( curr_node != NULL ) { if ( instance->cmp_keys(key, curr_node->key ) < 0 ) { prev_node = curr_node; // Remember prev. node curr_node = curr_node->left; // Continue search in left subtree } else if ( instance->cmp_keys(key, curr_node->key ) >= 0 ) { prev_node = curr_node; // Remember prev. node curr_node = curr_node->right; // Continue search in right subtree } } q = avl_new_node(key, data); q->height = 1; q->parent = prev_node; if ( instance->cmp_keys(key, prev_node->key) < 0 ) { prev_node->left = q; } else { prev_node->right = q; } x = y = z = q; while ( x != NULL ) { if ( avl_diff_height(x->left, x->right) <= 1) { z = y; y = x; x = x->parent; } else { break; } } if ( x != NULL ) { avl_trinode_restructure(instance, x, y, z); } return; }
avl_node * avl_find_node(sb_avl * instance, void * key) { avl_node * tmp; tmp = avl_finder(key, avl_root(instance), instance->cmp_keys); if (tmp == NULL) { return NULL; } else { return tmp; } }
avl_node *avl_remove_rebalance_r(avl_node *p){//mirror image of avl_remove_rebalance_l avl_node *n = p->left; if(n->balance != 1){ avl_rotate_l(p); p->balance -= n->balance++;//if n is -1, n and p become 0, otherwise n is 0 and they become +1 and -1. Note the -= needn't be flipped since -- was return n->balance ? avl_root(n) : avl_remove_retrace(n); } avl_rotate_r(n); avl_rotate_l(p); p->balance = +(n->parent->balance == -1); n->balance = -(n->parent->balance == 1); n->parent->balance = 0; return avl_remove_retrace(n->parent); }
avl_node *avl_remove_rebalance_l(avl_node *p){//do not try to understand this until you understand avl_insert_rebalance_r avl_node *n = p->right;//If we've become off balance by a left REMOVAL there must be a right child if(n->balance != -1){//not the right-left case avl_rotate_r(p);//nb. the pointers n and p point to the same nodes but now n is the parent p->balance -= n->balance--;//if n is +1, n and p become 0, otherwise n is 0 and they become -1 and +1 return n->balance ? avl_root(n) : avl_remove_retrace(n);//if n->balance becomes 0 by removal we still have height decrease to propagate }//right-left case. This is exactly the same as insertion whereas the previous part included a right-even case not present in insertion avl_rotate_l(n); avl_rotate_r(p); p->balance = -(n->parent->balance == 1); n->balance = +(n->parent->balance == -1); n->parent->balance = 0; return avl_remove_retrace(n->parent); }
void avl_delete(sb_avl * instance, avl_node * p) { /** Case 1: p has no children **/ if (p->left == NULL && p->right == NULL) { /** Case 1a: p is the root **/ if (p == avl_root(instance)) { free(avl_root(instance)); return; } avl_node * parent = p->parent; if (parent->left == p) { parent->left = NULL; } else { parent->right = NULL; } avl_recomp_height(parent); avl_rebalance(instance, parent); free(p); return; } /** Case 2: p has 1 child **/ if (p->right == NULL) { /** Case 2a: p is the root **/ if (p == avl_root(instance)) { // update the new root's parent instance->root->left->parent = NULL; // change the root to the new root instance->root = instance->root->left; // free the old root free(p); // re-compute heights avl_recomp_height(instance->root); // and re-balance avl_rebalance(instance, instance->root); return; } avl_node * parent = p->parent; if (parent->left == p) { parent->left = p->left; p->left->parent = parent; } else { parent->right = p->left; p->left->parent = parent; } free(p); avl_recomp_height(parent); avl_rebalance(instance, parent); return; } if (p->left == NULL) { if ( p == avl_root(instance) ) { // update the new root's parent instance->root->right->parent = NULL; // change the root instance->root = instance->root->right; // free the old root free(p); // re-compute heights avl_recomp_height(instance->root); // and re-balance avl_rebalance(instance, instance->root); return; } avl_node * parent = p->parent; if (parent->left == p) { parent->left = p->right; p->right->parent = parent; } else { parent->right = p->right; p->right->parent = parent; } free(p); avl_recomp_height(parent); avl_rebalance(instance, parent); return; } /** Case 3: p has 2 children **/ if ( p->right->left == NULL ) { // overwrite p with p->right. // This leaves p->right with no way to // get to it. So remove p->right. avl_node * tmp = p->right; p->key = p->right->key; p->value = p->right->value; p->right = p->right->right; free(tmp); avl_recomp_height(p->parent); avl_rebalance(instance, p->parent); return; } avl_node * succ = p->right; avl_node * succParent; while ( succ->left != NULL ) { succ = succ->left; } p->key = succ->key; p->value = succ->value; succParent = succ->parent; succParent->left = succ->right; free(succ); avl_recomp_height(succParent); avl_rebalance(instance, succParent); return; }