static void verify_tree (c_avl_node_t *n) { if (n == NULL) return; verify_tree (n->left); verify_tree (n->right); assert ((BALANCE (n) >= -1) && (BALANCE (n) <= 1)); assert ((n->parent == NULL) || (n->parent->right == n) || (n->parent->left == n)); } /* void verify_tree */
static void balance(t_avl const *const avl, t_node **const root) { int b = BALANCE(*root) / 2; if (b) { int const side = (1 - b) / 2; if (BALANCE((*root)->node[side]) == -b) rotate(avl, &(*root)->node[side], !side); *root = rotate(avl, root, side); } if (*root != nil) (*root)->height = 1 + MAX((*root)->node[0]->height, (*root)->node[1]->height); }
static void rebalance (c_avl_tree_t *t, c_avl_node_t *n) { int b_top; int b_bottom; while (n != NULL) { b_top = BALANCE (n); assert ((b_top >= -2) && (b_top <= 2)); if (b_top == -2) { assert (n->right != NULL); b_bottom = BALANCE (n->right); assert ((b_bottom >= -1) && (b_bottom <= 1)); if (b_bottom == 1) n = rotate_right_left (t, n); else n = rotate_left (t, n); } else if (b_top == 2) { assert (n->left != NULL); b_bottom = BALANCE (n->left); assert ((b_bottom >= -1) && (b_bottom <= 1)); if (b_bottom == -1) n = rotate_left_right (t, n); else n = rotate_right (t, n); } else { int height = calc_height (n); if (height == n->height) break; n->height = height; } assert (n->height == calc_height (n)); n = n->parent; } /* while (n != NULL) */ } /* void rebalance */
/* deletion */ static void __remove(t_avl const *const avl, t_node **const root, void *val) { if (*root == nil) return; if (!avl->hook_cmp((*root)->val, val)) { if ((*root = rotate(avl, root, BALANCE(*root) < 0)) == nil) return; } __remove(avl, &(*root)->node[avl->hook_cmp(val, (*root)->val) < 0], val); balance(avl, root); }
static node_t * avl_single(node_t *root, int dir) { node_t *save = root->link[!dir]; int rlh, rrh, slh; root->link[!dir] = save->link[dir]; save->link[dir] = root; rlh = height(root->link[0]); rrh = height(root->link[1]); slh = height(save->link[!dir]); BALANCE(root) = avl_max(rlh, rrh) + 1; BALANCE(save) = avl_max(slh, BALANCE(root)) + 1; return save; }
LIB_EXPORT rc_t CC BSTreeInsert ( BSTree *bt, BSTNode *n, int64_t ( CC * sort ) ( const BSTNode *n, const BSTNode *p ) ) { if ( bt != NULL && n != NULL ) { int64_t diff; BSTNode *p = bt -> root; BSTNode *q = NULL; BSTNode *y = NULL; while ( p != NULL ) { diff = ( * sort ) ( n, p ); q = p; if ( BALANCE ( p ) != 0 ) y = p; p = p -> child [ diff > 0 ]; } n -> par = q; n -> child [ 0 ] = n -> child [ 1 ] = NULL; if ( q == NULL ) bt -> root = n; else { q -> child [ diff > 0 ] = n; /* run a trace-back */ for ( p = n; q != y; ) { /* this is safe because q has 0 balance */ BSTNode *z = q -> par; if ( q -> child [ 0 ] == p ) SET_BALANCE ( q, LEFT ); else SET_BALANCE ( q, RIGHT ); p = q; q = z; } /* rebalance */ if ( q != NULL ) RebalanceAfterInsert ( & bt -> root, q, p ); } } /* never fails in this implementation */ return 0; }
static void CC RebalanceAfterInsert ( BSTNode **root, BSTNode *y, BSTNode *x ) { BSTNode *w, *z; /* detect left insertion */ if ( y -> child [ 0 ] == x ) { /* if y was right-heavy, done */ if ( RIGHT_HEAVY ( y ) ) { CLR_BALANCE ( y, RIGHT ); return; } /* rebalance left insertion */ w = RebalanceLeft ( y, x ); } /* right insertion */ else { /* if y was left-heavy, done */ if ( LEFT_HEAVY ( y ) ) { CLR_BALANCE ( y, LEFT ); return; } /* rebalance right insertion */ w = RebalanceRight ( y, x ); } /* fix parent to child */ assert ( BALANCE ( w ) == 0 ); z = w -> par; if ( z == 0 ) * root = w; else z -> child [ z -> child [ 1 ] == y ] = w; }
BSTNode* CC RotateRightAtXLeftAtY ( BSTNode *y, BSTNode *x ) { BSTNode *w = x -> child [ 0 ]; BSTNode *z = w -> child [ 1 ]; x -> child [ 0 ] = z; if ( z != 0 ) SET_PARENT ( z, x ); z = w -> child [ 0 ]; w -> child [ 1 ] = x; y -> child [ 1 ] = z; w -> child [ 0 ] = y; switch ( BALANCE ( w ) ) { case 0: w -> par = PARENT ( y ); x -> par = w; y -> par = w; break; case LEFT: w -> par = PARENT ( y ); SET_PARBAL ( x, w, RIGHT ); y -> par = w; break; case RIGHT: w -> par = PARENT ( y ); x -> par = w; SET_PARBAL ( y, w, LEFT ); break; } /* patch parent link */ if ( z != 0 ) SET_PARENT ( z, y ); return w; }
static int _remove (c_avl_tree_t *t, c_avl_node_t *n) { assert ((t != NULL) && (n != NULL)); if ((n->left != NULL) && (n->right != NULL)) { c_avl_node_t *r; /* replacement node */ if (BALANCE (n) > 0) /* left subtree is higher */ { assert (n->left != NULL); r = c_avl_node_prev (n); } else /* right subtree is higher */ { assert (n->right != NULL); r = c_avl_node_next (n); } assert ((r->left == NULL) || (r->right == NULL)); /* copy content */ n->key = r->key; n->value = r->value; n = r; } assert ((n->left == NULL) || (n->right == NULL)); if ((n->left == NULL) && (n->right == NULL)) { /* Deleting a leave is easy */ if (n->parent == NULL) { assert (t->root == n); t->root = NULL; } else { assert ((n->parent->left == n) || (n->parent->right == n)); if (n->parent->left == n) n->parent->left = NULL; else n->parent->right = NULL; rebalance (t, n->parent); } free_node (n); } else if (n->left == NULL) { assert (BALANCE (n) == -1); assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n)); if (n->parent == NULL) { assert (t->root == n); t->root = n->right; } else if (n->parent->left == n) { n->parent->left = n->right; } else { n->parent->right = n->right; } n->right->parent = n->parent; if (n->parent != NULL) rebalance (t, n->parent); n->right = NULL; free_node (n); } else if (n->right == NULL) { assert (BALANCE (n) == 1); assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n)); if (n->parent == NULL) { assert (t->root == n); t->root = n->left; } else if (n->parent->left == n) { n->parent->left = n->left; } else { n->parent->right = n->left; } n->left->parent = n->parent; if (n->parent != NULL) rebalance (t, n->parent); n->left = NULL; free_node (n); } else { assert (0); } return (0); } /* void *_remove */
extern int avl_remove(node_t **rootaddr, PyObject *key) { node_t *root = *rootaddr; int cmp_res; if (root != NULL) { node_t *it, *up[32]; int upd[32], top = 0; it = root; for (;;) { if (it == NULL) return 0; cmp_res = ct_compare(KEY(it), key); if (cmp_res == 0) break; upd[top] = (cmp_res < 0); up[top++] = it; it = it->link[upd[top - 1]]; } if (it->link[0] == NULL || it->link[1] == NULL) { int dir = it->link[0] == NULL; if (top != 0) up[top - 1]->link[upd[top - 1]] = it->link[dir]; else root = it->link[dir]; ct_delete_node(it); } else { node_t *heir = it->link[1]; upd[top] = 1; up[top++] = it; while ( heir->link[0] != NULL ) { upd[top] = 0; up[top++] = heir; heir = heir->link[0]; } ct_swap_data(it, heir); up[top - 1]->link[up[top - 1] == it] = heir->link[1]; ct_delete_node(heir); } while (--top >= 0) { int lh = height(up[top]->link[upd[top]]); int rh = height(up[top]->link[!upd[top]]); int max = avl_max(lh, rh); BALANCE(up[top]) = max + 1; if (lh - rh == -1) break; if (lh - rh <= -2) { node_t *a = up[top]->link[!upd[top]]->link[upd[top]]; node_t *b = up[top]->link[!upd[top]]->link[!upd[top]]; if (height(a) <= height(b)) up[top] = avl_single(up[top], upd[top]); else up[top] = avl_double(up[top], upd[top]); if (top != 0) up[top - 1]->link[upd[top - 1]] = up[top]; else root = up[0]; } } } (*rootaddr) = root; return 1; }
extern int avl_insert(node_t **rootaddr, PyObject *key, PyObject *value) { node_t *root = *rootaddr; if (root == NULL) { root = avl_new_node(key, value); if (root == NULL) return -1; } else { node_t *it, *up[32]; int upd[32], top = 0; int done = 0; int cmp_res; it = root; for (;;) { cmp_res = ct_compare(KEY(it), key); if (cmp_res == 0) { Py_XDECREF(VALUE(it)); VALUE(it) = value; Py_INCREF(value); return 0; } upd[top] = (cmp_res < 0); up[top++] = it; if (it->link[upd[top - 1]] == NULL) break; it = it->link[upd[top - 1]]; } it->link[upd[top - 1]] = avl_new_node(key, value); if (it->link[upd[top - 1]] == NULL) return -1; while (--top >= 0 && !done) { int lh, rh, max; cmp_res = ct_compare(KEY(up[top]), key); lh = height(up[top]->link[upd[top]]); rh = height(up[top]->link[!upd[top]]); if (lh - rh == 0) done = 1; if (lh - rh >= 2) { node_t *a = up[top]->link[upd[top]]->link[upd[top]]; node_t *b = up[top]->link[upd[top]]->link[!upd[top]]; if (height( a ) >= height( b )) up[top] = avl_single(up[top], !upd[top]); else up[top] = avl_double(up[top], !upd[top]); if (top != 0) up[top - 1]->link[upd[top - 1]] = up[top]; else root = up[0]; done = 1; } lh = height(up[top]->link[upd[top]]); rh = height(up[top]->link[!upd[top]]); max = avl_max(lh, rh); BALANCE(up[top]) = max + 1; } } (*rootaddr) = root; return 1; }
/* BSTreeUnlink * removes a node from tree */ static void CC RebalanceAfterUnlink ( BSTNode **root, BSTNode *q, int dir ) { while ( q != 0 ) { BSTNode *w, *x, *y = q; q = PARENT ( q ); if ( ! dir ) { if ( q && q -> child [ 1 ] == y ) dir = 1; /* simulate an increment of balance */ switch ( BALANCE ( y ) ) { case 0: SET_BALANCE ( y, RIGHT ); return; case LEFT: CLR_BALANCE ( y, LEFT ); break; case RIGHT: /* y has just become ++ */ x = y -> child [ 1 ]; if ( LEFT_HEAVY ( x ) ) { w = RotateRightAtXLeftAtY ( y, x ); if ( q == 0 ) * root = w; else q -> child [ dir ] = w; } else { w = y -> child [ 1 ] = x -> child [ 0 ]; x -> child [ 0 ] = y; SET_PARENT ( x, q ); SET_PARENT ( y, x ); if ( w != 0 ) SET_PARENT ( w, y ); if ( q == 0 ) * root = x; else q -> child [ dir ] = x; if ( BALANCE ( x ) == 0 ) { SET_BALANCE ( x, LEFT ); SET_PARBAL ( y, x, RIGHT ); return; } ZERO_BALANCE ( x ); ZERO_BALANCE ( y ); /* y = x; */ } break; } } /* symmetric case */ else { if ( q && q -> child [ 0 ] == y ) dir = 0; switch ( BALANCE ( y ) ) { case 0: SET_BALANCE ( y, LEFT ); return; case LEFT: /* y has just become -- */ x = y -> child [ 0 ]; if ( RIGHT_HEAVY ( x ) ) { w = RotateLeftAtXRightAtY ( y, x ); if ( q == 0 ) * root = w; else q -> child [ dir ] = w; } else { w = x -> child [ 1 ]; y -> child [ 0 ] = w; x -> child [ 1 ] = y; SET_PARENT ( x, q ); SET_PARENT ( y, x ); if ( w != 0 ) SET_PARENT ( w, y ); if ( q == 0 ) * root = x; else q -> child [ dir ] = x; if ( BALANCE ( x ) == 0 ) { SET_BALANCE ( x, RIGHT ); SET_PARBAL ( y, x, LEFT ); return; } ZERO_BALANCE ( x ); ZERO_BALANCE ( y ); /* y = x; */ } break; case RIGHT: CLR_BALANCE ( y, RIGHT ); break; } } } }
/* BSTreeInsertUnique * insert an object within tree, but only if unique * "sort" function returns equivalent of "item" - "n" * returns non-NULL "n" upon match or NULL on success */ LIB_EXPORT rc_t CC BSTreeInsertUnique ( BSTree *bt, BSTNode *n, BSTNode **exist, int64_t ( CC * sort ) ( const BSTNode *n, const BSTNode *p ) ) { if ( bt != NULL && n != NULL ) { int64_t diff; BSTNode *p = bt -> root; BSTNode *q = NULL; BSTNode *y = NULL; while ( p != NULL ) { diff = ( * sort ) ( n, p ); if ( diff == 0 ) { /* fail to insert */ if ( exist != NULL ) * exist = p; return RC ( rcCont, rcTree, rcInserting, rcNode, rcExists ); } q = p; if ( BALANCE ( p ) != 0 ) y = p; p = p -> child [ diff > 0 ]; } n -> par = q; n -> child [ 0 ] = n -> child [ 1 ] = NULL; if ( q == NULL ) bt -> root = n; else { q -> child [ diff > 0 ] = n; /* run a trace-back */ for ( p = n; q != y; ) { /* this is safe because q has 0 balance */ BSTNode *z = q -> par; if ( q -> child [ 0 ] == p ) SET_BALANCE ( q, LEFT ); else SET_BALANCE ( q, RIGHT ); p = q; q = z; } /* rebalance */ if ( q != NULL ) RebalanceAfterInsert ( & bt -> root, q, p ); } } /* only fails on existing item in this implementation */ return 0; }