/* This is a copy-cat of the previous loop, * with the exception that the heuristic to break * the loop is different. */ static inline void avl_rebalance_after_delete(struct rope_node ***path, struct rope_node ***p_end) { while (p_end > path) { struct rope_node *left = **p_end--; struct rope_node *parent = **p_end; int mirror = left != parent->link[0]; struct rope_node *right = parent->link[!mirror]; int left_height = rope_node_height(left); int right_height = rope_node_height(right); parent->height = MAX(left_height, right_height) + 1; /* * Right was taller, and we deleted from the left. * We can break the loop since there can be no * changes in height up in the route. */ if (left_height - right_height == -1) break; if (left_height - right_height <= -2) { struct rope_node *r_left = right->link[mirror]; struct rope_node *r_right = right->link[!mirror]; int r_left_height = rope_node_height(r_left); int r_right_height = rope_node_height(r_right); if (r_left_height <= r_right_height) **p_end = avl_rotate_single(parent, mirror); else **p_end = avl_rotate_double(parent, mirror); } } }
void *avl_remove(struct avl_tree *tree, void *key) { struct avl_node *it = tree->root; struct avl_node *up[AVL_MAX_HEIGHT]; int upd[AVL_MAX_HEIGHT], top = 0, cmp; paranoia(-500182, !it); // paranoia if not found // while ((cmp = memcmp(it->key, key, tree->key_size)) ) { while ((cmp = memcmp(it->key, key, tree->key_size)) || (it->link[0] && !memcmp(it->link[0]->key, key, tree->key_size))) { // Push direction and node onto stack upd[top] = (cmp < 0); up[top] = it; top++; if (!(it = it->link[(cmp < 0)])) return NULL; } // remember and return the found key. It might have been another one than intended key = it->key; // Remove the node: if (!(it->link[0] && it->link[1])) { // at least one child is NULL: // Which child is not null? int dir = !(it->link[0]); /* Fix parent */ if (top) { up[top - 1]->link[upd[top - 1]] = it->link[dir]; if (it->link[dir]) it->link[dir]->up = up[top - 1]; } else { tree->root = it->link[dir]; if (tree->root) tree->root->up = NULL; } debugFree(it, 1327); } else { // both childs NOT NULL: // Find the inorder successor struct avl_node *heir = it->link[1]; // Save the path upd[top] = 1; up[top] = it; top++; while (heir->link[0]) { upd[top] = 0; up[top] = heir; top++; heir = heir->link[0]; } // Swap data it->key = heir->key; // Unlink successor and fix parent up[top - 1]->link[ (up[top - 1] == it) ] = heir->link[1]; if ( heir->link[1]) heir->link[1]->up = up[top - 1]; debugFree(heir, 2327); } // Walk back up the search path while (--top >= 0) { int lh = avl_height(up[top]->link[upd[top]]); int rh = avl_height(up[top]->link[!upd[top]]); int max = avl_max(lh, rh); /* Update balance factors */ up[top]->balance = max + 1; // Terminate or re-balance as necessary: if (lh - rh >= 0) // re-balance upper path... continue; if (lh - rh == -1) // balance for upper path unchanged! break; if (!(up[top]) || !(up[top]->link[!upd[top]])) { dbgf(DBGL_SYS, DBGT_ERR, "up(top) %p link %p lh %d rh %d", (void*)(up[top]), (void*)((up[top]) ? (up[top]->link[!upd[top]]) : NULL), lh, rh); paranoia(-500187, (!(up[top]))); paranoia(-500188, (!(up[top]->link[!upd[top]]))); } /* paranoia(-500183, (lh - rh <= -3) ); paranoia(-500185, (lh - rh == 2) ); paranoia(-500186, (lh - rh >= 3) ); */ // if (lh - rh <= -2): rebalance here and upper path struct avl_node *a = up[top]->link[!upd[top]]->link[upd[top]]; struct avl_node *b = up[top]->link[!upd[top]]->link[!upd[top]]; if (avl_height(a) <= avl_height(b)) up[top] = avl_rotate_single(up[top], upd[top]); else up[top] = avl_rotate_double(up[top], upd[top]); // Fix parent: if (top) { up[top - 1]->link[upd[top - 1]] = up[top]; up[top]->up = up[top - 1]; } else { tree->root = up[0]; tree->root->up = NULL; } } return key; }
/** Rebalance the tree. */ static inline void avl_rebalance_after_insert(struct rope_node ***path, struct rope_node ***p_end, int insert_height) { while (p_end > path) { struct rope_node *left = **p_end--; struct rope_node *parent = **p_end; /* * To use the same rotation functions, set mirror * to 1 if left is right and right is left. */ int mirror = left != parent->link[0]; struct rope_node *right = parent->link[!mirror]; int left_height = rope_node_height(left); int right_height = rope_node_height(right); parent->height = MAX(left_height, right_height) + 1; /* * Rotations flattened the tree, so there is no * further changes in height up the insertion * path. */ if (left_height == right_height) break; /* * We've been adding a new child (children) to the * 'left' subtree, so it couldn't get shorter. * The old difference between subtrees was in the * range -1..1. So the new difference can only be * in the range -1..1 + height(new_node). */ if (left_height - right_height >= 2) { struct rope_node *l_left = left->link[mirror]; struct rope_node *l_right = left->link[!mirror]; int l_left_height = rope_node_height(l_left); int l_right_height = rope_node_height(l_right); /* * Rotate in the direction, opposite to * the skew. E.g. if we have two left-left * nodes hanging off the tree, rotate the * parent clockwise. If we have a left * node with a right child, rotate the * child counterclockwise, and then the whole * thing clockwise. */ if (l_left_height >= l_right_height) **p_end = avl_rotate_single(parent, !mirror); else **p_end = avl_rotate_double(parent, !mirror); /* * If we inserted only one node, no more * than 1 rotation is required (see * D. Knuth, Introduction to Algorithms, * vol. 3.). For 2 nodes, its max * 2 rotations. */ if (l_left_height != l_right_height && --insert_height == 0) break; } } }
void avl_insert(struct avl_tree *tree, void *key) { if (tree->root) { struct avl_node *it = tree->root; struct avl_node *up[AVL_MAX_HEIGHT]; int upd[AVL_MAX_HEIGHT], top = 0; int done = 0; /* Search for an empty link, save the path */ for (;;) { /* Push direction and node onto stack */ // upd[top] = memcmp(it->key, key, tree->key_size) < 0; upd[top] = memcmp(it->key, key, tree->key_size) <= 0; up[top++] = it; if (it->link[upd[top - 1]] == NULL) break; it = it->link[upd[top - 1]]; } /* Insert a new node at the bottom of the tree */ it->link[upd[top - 1]] = avl_create_node(key); it->link[upd[top - 1]]->up = it; paranoia(-500178, (it->link[upd[top - 1]] == NULL)); /* Walk back up the search path */ while (--top >= 0 && !done) { int lh, rh, max; lh = avl_height(up[top]->link[upd[top]]); rh = avl_height(up[top]->link[!upd[top]]); /* Terminate or rebalance as necessary */ if (lh - rh == 0) done = 1; if (lh - rh >= 2) { struct avl_node *a = up[top]->link[upd[top]]->link[upd[top]]; struct avl_node *b = up[top]->link[upd[top]]->link[!upd[top]]; if (avl_height(a) >= avl_height(b)) up[top] = avl_rotate_single(up[top], !upd[top]); else up[top] = avl_rotate_double(up[top], !upd[top]); /* Fix parent */ if (top != 0) { up[top - 1]->link[upd[top - 1]] = up[top]; up[top]->up = up[top - 1]; } else { tree->root = up[0]; up[0]->up = NULL; } done = 1; } /* Update balance factors */ lh = avl_height(up[top]->link[upd[top]]); rh = avl_height(up[top]->link[!upd[top]]); max = avl_max(lh, rh); up[top]->balance = max + 1; } } else { tree->root = avl_create_node(key); paranoia( -500179, (tree->root==NULL)); } return; }