int fwAvlInsert(uint32_t key, void* data, struct FwAvlTree* tree) { int is_left; struct FwAvlNode* parent; struct FwAvlNode* right; struct FwAvlNode* left; struct FwAvlNode* unbalanced; struct FwAvlNode* node; if(do_lookup(key, tree, &parent, &unbalanced, &is_left) != NULL) return 1; if(!(node = new_node(key, data))) return -1; tree->count++; if(parent == NULL) { tree->root = node; tree->first = node; tree->last = node; return 0; } if(is_left != 0) { if(parent == tree->first) tree->first = node; } else { if(parent == tree->last) tree->last = node; } set_parent(parent, node); set_child(node, parent, is_left); while(1) { if(parent->left == node) dec_balance(parent); else inc_balance(parent); if(parent == unbalanced) break; node = parent; parent = get_parent(node); } switch(get_balance(unbalanced)) { case 1: case -1: tree->height++; break; case 0: break; case 2: right = unbalanced->right; if(get_balance(right) == 1) { set_balance(0, unbalanced); set_balance(0, right); } else { switch(get_balance(right->left)) { case 1: set_balance(-1, unbalanced); set_balance(0, right); break; case 0: set_balance(0, unbalanced); set_balance(0, right); break; case -1: set_balance(0, unbalanced); set_balance(1, right); break; } set_balance(0, right->left); rotate_right(right, tree); } rotate_left(unbalanced, tree); break; case -2: left = unbalanced->left; if(get_balance(left) == -1) { set_balance(0, unbalanced); set_balance(0, left); } else { switch(get_balance(left->right)) { case 1: set_balance(0, unbalanced); set_balance(-1, left); break; case 0: set_balance(0, unbalanced); set_balance(0, left); break; case -1: set_balance(1, unbalanced); set_balance(0, left); break; } set_balance(0, left->right); rotate_left(left, tree); } rotate_right(unbalanced, tree); break; } return 0; }
/* Insertion never needs more than 2 rotations */ struct avltree_node *avltree_insert(struct avltree_node *node, struct avltree *tree) { struct avltree_node *key, *parent, *unbalanced; int is_left; key = do_lookup(node, tree, &parent, &unbalanced, &is_left); if (key) return key; INIT_NODE(node); if (!parent) { tree->root = node; tree->first = tree->last = node; tree->height++; return NULL; } if (is_left) { if (parent == tree->first) tree->first = node; } else { if (parent == tree->last) tree->last = node; } set_parent(parent, node); set_child(node, parent, is_left); for (;;) { if (parent->left == node) dec_balance(parent); else inc_balance(parent); if (parent == unbalanced) break; node = parent; parent = get_parent(parent); } switch (get_balance(unbalanced)) { case 1: case -1: tree->height++; /* fall through */ case 0: break; case 2: { struct avltree_node *right = unbalanced->right; if (get_balance(right) == 1) { set_balance(0, unbalanced); set_balance(0, right); } else { switch (get_balance(right->left)) { case 1: set_balance(-1, unbalanced); set_balance( 0, right); break; case 0: set_balance(0, unbalanced); set_balance(0, right); break; case -1: set_balance(0, unbalanced); set_balance(1, right); break; } set_balance(0, right->left); rotate_right(right, tree); } rotate_left(unbalanced, tree); break; } case -2: { struct avltree_node *left = unbalanced->left; if (get_balance(left) == -1) { set_balance(0, unbalanced); set_balance(0, left); } else { switch (get_balance(left->right)) { case 1: set_balance( 0, unbalanced); set_balance(-1, left); break; case 0: set_balance(0, unbalanced); set_balance(0, left); break; case -1: set_balance(1, unbalanced); set_balance(0, left); break; } set_balance(0, left->right); rotate_left(left, tree); } rotate_right(unbalanced, tree); break; } } return NULL; }
/* 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--; }
/* Insertion never needs more than 2 rotations */ struct avltree_node *avltree_insert(struct avltree_node *node, struct avltree *tree) { struct avltree_node *parent = 0, *unbalanced = tree->root; bool is_left; // Find a suitable parent. for (struct avltree_node *next_parent = tree->root; next_parent != 0;) { parent = next_parent; if (get_balance(parent) != 0) unbalanced = parent; int cmp_r = tree->cmp_fn(parent, node); if (cmp_r == 0) { if (tree->unique_index) return parent; // For non unique indexes any insert direction is acceptable. if (parent->left == 0) { is_left = true; break; } else if (parent->right == 0) { is_left = false; break; } else { // Be smart and travel to the least balanced subtree to minimize balancing overhead. next_parent = (get_balance(parent) <= 0)? parent->left: parent->right; } } else { is_left = (cmp_r > 0); next_parent = is_left? parent->left: parent->right; } } INIT_NODE(node); if (!parent) { tree->root = node; tree->first = tree->last = node; tree->height++; return 0; } if (is_left) { if (parent == tree->first) tree->first = node; } else { if (parent == tree->last) tree->last = node; } set_parent(parent, node); set_child(node, parent, is_left); for (;;) { if (parent->left == node) dec_balance(parent); else inc_balance(parent); if (parent == unbalanced) { for (;;) { node = parent; node->count++; if (is_root(node)) break; parent = get_parent(parent); } break; } node = parent; node->count++; parent = get_parent(parent); } switch (get_balance(unbalanced)) { case 1: case -1: tree->height++; /* fall through */ case 0: break; case 2: { struct avltree_node *right = unbalanced->right; if (get_balance(right) == 1) { set_balance(0, unbalanced); set_balance(0, right); } else { switch (get_balance(right->left)) { case 1: set_balance(-1, unbalanced); set_balance(0, right); break; case 0: set_balance(0, unbalanced); set_balance(0, right); break; case -1: set_balance(0, unbalanced); set_balance(1, right); break; } set_balance(0, right->left); rotate_right(right, tree); } rotate_left(unbalanced, tree); break; } case -2: { struct avltree_node *left = unbalanced->left; if (get_balance(left) == -1) { set_balance(0, unbalanced); set_balance(0, left); } else { switch (get_balance(left->right)) { case 1: set_balance(0, unbalanced); set_balance(-1, left); break; case 0: set_balance(0, unbalanced); set_balance(0, left); break; case -1: set_balance(1, unbalanced); set_balance(0, left); break; } set_balance(0, left->right); rotate_left(left, tree); } rotate_right(unbalanced, tree); break; } } return 0; }