static void destroy_subtree(AvlTree *tree, AvlNode **subtree_root) { if ((*subtree_root) == 0) return; AvlNode *this_node = (*subtree_root); while (TRUE) if (this_node->links.right) this_node = this_node->links.right; else if (this_node->links.left) this_node = this_node->links.left; else { AvlNode *node_to_delete = this_node; this_node = this_node->links.parent; free_avl_node(node_to_delete, tree->destroyKey); if (node_to_delete == (*subtree_root) || this_node == 0) break; else if (node_to_delete == this_node->links.right) this_node->links.right = 0; else this_node->links.left = 0; } (*subtree_root) = 0; }
VALUE_TYPE delete_node(AvlTree *tree, const KEY_TYPE key) { AvlNode *parent_node = 0; AvlNode *this_node = *search_routine(key, &tree->tree_root, &parent_node, tree->compareKeys); if (this_node) { VALUE_TYPE res = this_node->value; rebalance_shrunk(this_node, &tree->tree_root); free_avl_node(this_node, tree->destroyKey); return res; } else return 0; }
/* * used to recursively destroy (free up) all nodes below 'node' */ static void avl_node_destroy_nodes (avl_tree_t *tree, avl_node_t *node, int leave_parent_consistent) { avl_node_t *parent, *left, *right; // end node if (NULL == node) return; left = node->left; right = node->right; if (leave_parent_consistent) { parent = node->parent; if (parent) { if (parent->left == node) { parent->left = NULL; } else if (parent->right == node) { parent->right = NULL; } else { assert(0); } } else { tree->root_node = NULL; } } // done with this one. Freeing this here before we get deep into // recursion frees up the nodes much more quickly without building // up all the stack of nodes during recursion. // free_avl_node(tree, node); // recurse on; since we will be deleting all these // nodes, there is no need to leave the parent's // pointers consistent. // avl_node_destroy_nodes(tree, left, 0); avl_node_destroy_nodes(tree, right, 0); }
static int thread_unsafe_avl_tree_remove (avl_tree_t *tree, void *data_to_be_removed, void **actual_data_removed) { avl_node_t *node, *to_be_deleted; avl_node_t *parent, *unbalanced; avl_node_t *left; avl_node_t *right; avl_node_t *next; int is_left; /* being traversed, cannot access */ if (tree->cannot_be_modified) return EBUSY; /* find the matching node first */ node = avl_lookup_engine(tree, data_to_be_removed, &parent, &unbalanced, &is_left); /* not there */ if (!node) { *actual_data_removed = NULL; return ENODATA; } /* if we are here, we found it */ *actual_data_removed = node->user_data; /* cache it for later freeing */ to_be_deleted = node; parent = node->parent; left = node->left; right = node->right; #if 0 if (node == tree->first_node) tree->first_node = avl_tree_next(node); if (node == tree->last_node) tree->last_node = avl_tree_prev(node); #endif 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_node = next; if (left && right) { next->balance = node->balance; next->left = left; left->parent = next; if (next != right) { parent = next->parent; next->parent = node->parent; node = next->right; parent->left = node; next->right = right; right->parent = next; is_left = 1; } else { next->parent = parent; parent = next; node = parent->right; is_left = 0; } assert(parent != NULL); } else node = next; if (node) node->parent = parent; while (parent) { int balance; node = parent; parent = parent->parent; if (is_left) { is_left = (parent && (parent->left == node)); balance = ++node->balance; if (balance == 0) /* case 1 */ continue; if (balance == 1) { /* case 2 */ goto END_OF_DELETE; } right = node->right; switch (right->balance) { case 0: /* case 3.1 */ node->balance = 1; right->balance = -1; rotate_left(node, tree); goto END_OF_DELETE; case 1: /* case 3.2 */ node->balance = 0; right->balance = 0; break; case -1: /* case 3.3 */ switch (right->left->balance) { case 1: node->balance = -1; right->balance = 0; break; case 0: node->balance = 0; right->balance = 0; break; case -1: node->balance = 0; right->balance = 1; break; } right->left->balance = 0; rotate_right(right, tree); } rotate_left(node, tree); } else { is_left = (parent && (parent->left == node)); balance = --node->balance; if (balance == 0) continue; if (balance == -1) { goto END_OF_DELETE; } left = node->left; switch (left->balance) { case 0: node->balance = -1; left->balance = 1; rotate_right(node, tree); goto END_OF_DELETE; case -1: node->balance = 0; left->balance = 0; break; case 1: switch (left->right->balance) { case 1: node->balance = 0; left->balance = -1; break; case 0: node->balance = 0; left->balance = 0; break; case -1: node->balance = 1; left->balance = 0; break; } left->right->balance = 0; rotate_left(left, tree); } rotate_right(node, tree); } } END_OF_DELETE: free_avl_node(tree, to_be_deleted); if (tree->n <= 0) { assert(tree->root_node == NULL); } else { assert(tree->root_node != NULL); } return 0; }