/* * Austin---Astonishing Universal Search Tree Interface Novelty * Copyright (C) 2000 Kaz Kylheku * Copyright (C) 2000 Carl van Tast * * Free Software License: * * All rights are reserved by the author, with the following exceptions: * Permission is granted to freely reproduce and distribute this software, * possibly in exchange for a fee, provided that this copyright notice appears * intact. Permission is also granted to adapt this software to produce * derivative works, as long as the modified versions carry this copyright * notice and additional notices stating that the work has been modified. * This source code may be translated into executable form and incorporated * into proprietary software; there is no requirement for such software to * contain a copyright notice related to this source. * * $Id: avl.c,v 1.3 2000/01/12 02:37:02 kaz Exp $ * $Name: austin_0_2 $ */ /* * Modified for use in ReactOS by arty */ #include "rtl.h" #include "udict.h" #include "tree.h" #include "macros.h" #define balance Balance #define BALANCED udict_balanced #define LEFTHEAVY udict_leftheavy #define RIGHTHEAVY udict_rightheavy #define EQUAL GenericEqual #define LESS GenericLessThan #define GREATER GenericGreaterThan int print_node(udict_t *ud, udict_node_t *node, int indent) { int i, rh = 0, lh = 0; char buf[100]; udict_node_t *nil = ud->BalancedRoot.Parent; for( i = 0; i < indent; i++ ) buf[i] = ' '; if( node == ud->BalancedRoot.Parent ) { sprintf(buf+i, "Nil\n"); DbgPrint("%s", buf); return 0; } else { sprintf(buf+i, "Node %p (parent %p: balance %d)\n", node, node->parent, node->Balance); DbgPrint("%s", buf); if( node->LeftChild != nil ) { sprintf(buf+i, "--> Left\n"); DbgPrint("%s", buf); lh = print_node(ud, node->LeftChild, indent+1); } if( node->RightChild != nil ) { sprintf(buf+i, "--> Right\n"); DbgPrint("%s", buf); rh = print_node(ud, node->RightChild, indent+1); } if (indent) { if (rh < lh - 1 || lh < rh - 1) { sprintf(buf+i, "warning: tree is too unbalanced %d vs %d\n", lh, rh); DbgPrint("%s", buf); } if (rh != lh && node->Balance == BALANCED) { sprintf(buf+i, "warning: tree says balanced, but %d vs %d\n", lh, rh); DbgPrint("%s", buf); } else if (lh <= rh && node->Balance == LEFTHEAVY) { sprintf(buf+i, "warning: tree says leftheavy but %d vs %d\n", lh, rh); DbgPrint("%s", buf); } else if (lh >= rh && node->Balance == RIGHTHEAVY) { sprintf(buf+i, "warning: tree says rightheavy but %d vs %d\n", lh, rh); DbgPrint("%s", buf); } } if (rh > lh) return 1+rh; else return 1+lh; } } void print_tree(udict_t *ud) { DbgPrint("TREE %x (Nil %x)\n", ud, ud->BalancedRoot.Parent); print_node(ud, &ud->BalancedRoot, 0); } void avl_init(udict_t *ud) { ud->BalancedRoot.left = ud->BalancedRoot.right = ud->BalancedRoot.parent = (udict_node_t*) ud->AllocateRoutine(ud, sizeof(udict_node_t)); ud->BalancedRoot.parent->left = ud->BalancedRoot.parent->right = ud->BalancedRoot.parent->parent = ud->BalancedRoot.parent; } void avl_deinit(udict_t *ud) { ud->FreeRoutine(ud, ud->BalancedRoot.parent); } static void RotateLeft(udict_node_t **top) { udict_node_t *parent = *top; udict_node_t *child = parent->right; child->parent = parent->parent; parent->right = child->left; parent->right->parent = parent; /* may change sentinel.parent */ child->left = parent; parent->parent = child; *top = child; }/*RotateLeft*/ static void RotateRight(udict_node_t **top) { udict_node_t *parent = *top; udict_node_t *child = parent->left; child->parent = parent->parent; parent->left = child->right; parent->left->parent = parent; /* may change sentinel.parent */ child->right = parent; parent->parent = child; *top = child; }/*RotateRight*/ static void FixBalance(udict_node_t **pnode, udict_avl_balance_t bal) { udict_node_t *node = *pnode; udict_node_t *child; udict_node_t *grandchild; if (node->balance == BALANCED) { node->balance = bal; }/*if*/ else if (node->balance != bal) { node->balance = BALANCED; }/*elsif*/ else { assert (node->balance == bal); if (bal == LEFTHEAVY) { child = node->left; if (child->balance == LEFTHEAVY) { node->balance = BALANCED; child->balance = BALANCED; RotateRight(pnode); }/*if*/ else if (child->balance == BALANCED) { /* only possible after delete */ node->balance = LEFTHEAVY; child->balance = RIGHTHEAVY; RotateRight(pnode); }/*elsif*/ else { assert (child->balance == RIGHTHEAVY); grandchild = child->right; if (grandchild->balance == LEFTHEAVY) { node->balance = RIGHTHEAVY; child->balance = BALANCED; }/*if*/ else if (grandchild->balance == RIGHTHEAVY) { node->balance = BALANCED; child->balance = LEFTHEAVY; }/*elsif*/ else { node->balance = BALANCED; child->balance = BALANCED; }/*else*/ grandchild->balance = BALANCED; RotateLeft(&node->left); RotateRight(pnode); }/*else*/ }/*if*/ else { assert (bal == RIGHTHEAVY); child = node->right; if (child->balance == RIGHTHEAVY) { node->balance = BALANCED; child->balance = BALANCED; RotateLeft(pnode); }/*if*/ else if (child->balance == BALANCED) { /* only possible after delete */ node->balance = RIGHTHEAVY; child->balance = LEFTHEAVY; RotateLeft(pnode); }/*elsif*/ else { assert (child->balance == LEFTHEAVY); grandchild = child->left; if (grandchild->balance == RIGHTHEAVY) { node->balance = LEFTHEAVY; child->balance = BALANCED; }/*if*/ else if (grandchild->balance == LEFTHEAVY) { node->balance = BALANCED; child->balance = RIGHTHEAVY; }/*elsif*/ else { node->balance = BALANCED; child->balance = BALANCED; }/*else*/ grandchild->balance = BALANCED; RotateRight(&node->right); RotateLeft(pnode); }/*else*/ }/*else*/ }/*else*/ }/*FixBalance*/ static int Insert(udict_t *ud, udict_node_t *what, udict_node_t **where, udict_node_t *parent) { udict_node_t *here = *where; int result; if (here == tree_null_priv(ud)) { *where = what; what->parent = parent; return 1; /* higher than before */ }/*if*/ else { result = ud->compare(ud, key(what), key(here)); assert (result != GenericEqual); if (result == LESS) { if (Insert(ud, what, &here->left, here)) { /* ** now left side is higher than before */ FixBalance(where, LEFTHEAVY); return ((*where)->balance != BALANCED); }/*if*/ }/*if*/ else { if (Insert(ud, what, &here->right, here)) { /* ** now right side is higher than before */ FixBalance(where, RIGHTHEAVY); return ((*where)->balance != BALANCED); }/*if*/ }/*else*/ }/*else*/ return 0; /* height not changed */ }/*Insert*/ void avl_insert_node(udict_t *ud, udict_node_t *node) { udict_node_t *nil = tree_null_priv(ud); node->left = nil; node->right = nil; node->balance = BALANCED; if (Insert(ud, node, &ud->BalancedRoot.left, nil)) { nil->balance = LEFTHEAVY; }/*if*/ if (ud->BalancedRoot.left == node) { node->parent = &ud->BalancedRoot; ud->BalancedRoot.balance = LEFTHEAVY; } ud->nodecount++; } void avl_delete_node(udict_t *ud, udict_node_t *node) { udict_node_t *nil = tree_null_priv(ud); udict_node_t *swap; udict_node_t *child; udict_node_t *parent; udict_tree_delete(ud, node, &swap, &child); #ifndef NDEBUG if (swap == node) { /* ** node had 0 or 1 child, ** child moved up to node's place */ if (child != nil) { assert ((child->left == nil) && (child->right == nil)); assert (child->balance == BALANCED); }/*if*/ }/*if*/ else { /* ** node had 2 children, ** swap was node's successor (in node's right subtree), ** swap has been inserted in node's place, ** child was swap->right, ** child has been moved to swap's place */ if (child != nil) { assert ((child->left == nil) && (child->right == nil)); assert (child->balance == BALANCED); }/*if*/ }/*else*/ #endif swap->balance = node->balance; /* ** In either case, child has been moved to the next higher level. ** So the balance of its new parent has to be checked. ** Note, that child->parent points to the node we are interested in, ** even if child == nil. */ parent = child->parent; if (parent == nil) { /* root has been deleted */ if (child == nil) { parent->balance = BALANCED; ud->BalancedRoot.left = nil; }/*if*/ }/*if*/ while (parent != &ud->BalancedRoot) { if ((parent->left == nil) && (parent->right == nil)) { assert (child == nil); parent->balance = BALANCED; /* propagate height reduction to upper level */ }/*if*/ else { udict_node_t **pparent; if (parent == parent->parent->left) pparent = &parent->parent->left; else pparent = &parent->parent->right; if (child == parent->left) { /* reduce parent's left height */ FixBalance(pparent, RIGHTHEAVY); }/*if*/ else { assert (child == parent->right); /* reduce parent's right height */ FixBalance(pparent, LEFTHEAVY); }/*else*/ /* ** parent and child are not valid now, ** pparent may point to new root of subtree */ parent = *pparent; }/*else*/ /* if subtree is balanced, then height is less than before */ if (parent->balance == BALANCED) { child = parent; parent = child->parent; }/*if*/ else break; }/*while*/ }/*avl_delete_node*/ void *avl_get_data(udict_node_t *here) { return data(here); } int avl_search(udict_t *ud, void *_key, udict_node_t *here, udict_node_t **where) { int result; if (avl_is_nil(ud, here)) return TableInsertAsLeft; result = ud->compare(ud, _key, key(here)); if (result == EQUAL) { *where = here; return TableFoundNode; } if (result == LESS) { if( here->left == tree_null_priv(ud) ) { *where = here; return TableInsertAsLeft; } return avl_search(ud, _key, here->left, where); }/*if*/ else { if( here->right == tree_null_priv(ud) ) { *where = here; return TableInsertAsRight; } return avl_search(ud, _key, here->right, where); }/*else*/ } int avl_is_nil(udict_t *ud, udict_node_t *node) { return tree_null_priv(ud) == node || &ud->BalancedRoot == node; } udict_node_t *avl_first(udict_t *ud) { return udict_tree_first(ud); } udict_node_t *avl_last(udict_t *ud) { return udict_tree_last(ud); } udict_node_t *avl_next(udict_t *ud, udict_node_t *prev) { udict_node_t *node = udict_tree_next(ud, prev); if( node == tree_null_priv(ud) || node == &ud->BalancedRoot ) return NULL; else return node; }