static void _insert_rebalance(struct avl *avl, struct avl_node *node, compare cmp) { struct avl_node *leaf, **parentp; for (leaf = node, node = node->parent; node != NULL; node = node->parent) { /* parent height no change means tree balance still */ if (node->height == HEIGHT(node)) return; SET_HEIGHT(node); /* rebalance */ if (ABS(DIFF_HEIGHT(node)) > 1) { if (node->parent) parentp = (node == node->parent->left) ? &node->parent->left : &node->parent->right; else parentp = &avl->root; if (cmp(leaf->value, node->value) == -1) { if (cmp(leaf->value, node->left->value) == 1) node->left = _left_rotate(node->left); *parentp = _right_rotate(node); } else { if (cmp(leaf->value, node->right->value) == -1) node->right = _right_rotate(node->right); *parentp = _left_rotate(node); } SET_HEIGHT((*parentp)); break; } } }
static void _remove_rebalance(struct avl *avl, struct avl_node *node, compare cmp) { struct avl_node **parentp; for (parentp = NULL; node != NULL; node = node->parent) { retry: SET_HEIGHT(node); /* rebalance */ if (ABS(DIFF_HEIGHT(node)) > 1) { if (node->parent) parentp = (node == node->parent->left) ? &node->parent->left : &node->parent->right; else parentp = &avl->root; /* left height > right height */ if (DIFF_HEIGHT(node) > 0) { if (node->left->right) node->left = _left_rotate(node->left); *parentp = _right_rotate(node); node = (*parentp)->left; } else { if (node->right->left) node->right = _right_rotate(node->right); *parentp = _left_rotate(node); node = (*parentp)->right; } SET_HEIGHT((*parentp)); goto retry; } } }
VOID new_tree(WORD sobj, WORD dobj, WORD dx, WORD dy) { WORD w, h; LONG maddr, tree, obspec; if (rcs_lock) hndl_locked(); else { switch (sobj) { case MENUICON: ini_tree(&maddr, NEWMENU); ins_tree(maddr, ROOT, MENU, dobj, dx, dy); break; case ALRTICON: ini_tree(&tree, ALRTPBX); obspec = GET_SPEC(tree, APBXIMG0); ini_tree(&maddr, NEWALRT); tree = ins_tree(maddr, ROOT, ALRT, dobj, dx, dy); if (tree != -1L) { SET_SPEC(tree, ALRTIMG, obspec); fix_alert(tree); } break; case PANLICON: case FREEICON: ini_tree(&maddr, NEWPANEL); tree = ins_tree(maddr, ROOT, (sobj == PANLICON)? PANL: FREE, dobj, dx, dy); if (tree != -1L) { SET_HEIGHT(tree, ROOT, view.g_h); SET_WIDTH(tree, ROOT, view.g_w); } break; case DIALICON: ini_tree(&maddr, NEWDIAL); tree = ins_tree(maddr, ROOT, DIAL, dobj, dx, dy); if (tree != -1L) { w = view.g_w; h = view.g_h; snap_wh(&w, &h); SET_HEIGHT(tree, ROOT, h); SET_WIDTH(tree, ROOT, w); } break; default: break; } } }
static struct avl_node *_right_rotate(struct avl_node *node) { struct avl_node *child = node->left; if (child) { child->parent = node->parent; node->left = child->right; if (node->left) node->left->parent = node; node->parent = child; child->right = node; SET_HEIGHT(node); SET_HEIGHT(child); } return child; }