void avltree_foreach_backward(struct avltree *tree, avltree_call_fn_t call) { struct avltree_node * i; struct avltree_node * n; for (i = avltree_last(tree); i; ) { n = avltree_prev(i); call(i); i = n; } }
/* Deletion might require up to log(n) rotations */ void avltree_remove(struct avltree_node *node, struct avltree *tree) { struct avltree_node *parent = get_parent(node); struct avltree_node *left = node->left; struct avltree_node *right = node->right; struct avltree_node *next; int is_left = is_left; if (node == tree->first) tree->first = avltree_next(node); if (node == tree->last) tree->last = avltree_prev(node); if (!left) next = right; else if (!right) next = left; else next = get_first(right); if (parent) { is_left = parent->left == node; set_child(next, parent, is_left); } else tree->root = next; if (left && right) { set_balance(get_balance(node), next); next->left = left; set_parent(next, left); if (next != right) { parent = get_parent(next); set_parent(get_parent(node), next); node = next->right; parent->left = node; is_left = 1; next->right = right; set_parent(next, right); } else { set_parent(parent, next); parent = next; node = parent->right; is_left = 0; } assert(parent != NULL); } else node = next; if (node) set_parent(parent, node); /* * At this point, 'parent' can only be null, if 'node' is the * tree's root and has at most one child. * * case 1: the subtree is now balanced but its height has * decreased. * * case 2: the subtree is mostly balanced and its height is * unchanged. * * case 3: the subtree is unbalanced and its height may have * been changed during the rebalancing process, see below. * * case 3.1: after a left rotation, the subtree becomes mostly * balanced and its height is unchanged. * * case 3.2: after a left rotation, the subtree becomes * balanced but its height has decreased. * * case 3.3: after a left and a right rotation, the subtree * becomes balanced or mostly balanced but its height has * decreased for all cases. */ while (parent) { int balance; node = parent; parent = get_parent(parent); if (is_left) { is_left = parent && parent->left == node; balance = inc_balance(node); if (balance == 0) /* case 1 */ continue; if (balance == 1) /* case 2 */ return; right = node->right; /* case 3 */ switch (get_balance(right)) { case 0: /* case 3.1 */ set_balance( 1, node); set_balance(-1, right); rotate_left(node, tree); return; case 1: /* case 3.2 */ set_balance(0, node); set_balance(0, right); break; case -1: /* case 3.3 */ switch (get_balance(right->left)) { case 1: set_balance(-1, node); set_balance( 0, right); break; case 0: set_balance(0, node); set_balance(0, right); break; case -1: set_balance(0, node); set_balance(1, right); break; } set_balance(0, right->left); rotate_right(right, tree); } rotate_left(node, tree); } else { is_left = parent && parent->left == node; balance = dec_balance(node); if (balance == 0) continue; if (balance == -1) return; left = node->left; switch (get_balance(left)) { case 0: set_balance(-1, node); set_balance(1, left); rotate_right(node, tree); return; case -1: set_balance(0, node); set_balance(0, left); break; case 1: switch (get_balance(left->right)) { case 1: set_balance(0, node); set_balance(-1, left); break; case 0: set_balance(0, node); set_balance(0, left); break; case -1: set_balance(1, node); set_balance(0, left); break; } set_balance(0, left->right); rotate_left(left, tree); } rotate_right(node, tree); } } tree->height--; }