1147 lines
32 KiB
C++
1147 lines
32 KiB
C++
/*++
|
|
|
|
Copyright (c) 1993-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
avl.h
|
|
|
|
Abstract:
|
|
|
|
AVL tree template class implementation
|
|
|
|
Author:
|
|
|
|
Bill Bolosky [bolosky] 1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
enum AVLBalance {
|
|
AVLNew, // Not yet inserted in a tree
|
|
AVLLeft, // Left side is one deeper than the right
|
|
AVLBalanced, // Left and right sides are evenly balanced
|
|
AVLRight, // Right side is one deeper than left
|
|
};
|
|
|
|
template<class elementClass> class AVLElement;
|
|
|
|
template<class elementClass> class AVLTree {
|
|
|
|
public:
|
|
AVLTree(
|
|
unsigned preallocateSize = 0);
|
|
|
|
~AVLTree(void);
|
|
|
|
elementClass *findFirstLessThanOrEqualTo(
|
|
elementClass *element);
|
|
|
|
elementClass *findFirstGreaterThan(
|
|
elementClass *element);
|
|
|
|
elementClass *findFirstGreaterThanOrEqualTo(
|
|
elementClass *element);
|
|
|
|
elementClass *findMin(void);
|
|
|
|
elementClass *findMax(void);
|
|
|
|
int empty(void);
|
|
|
|
unsigned size(void);
|
|
|
|
void check(void);
|
|
|
|
BOOLEAN insert(
|
|
elementClass *element);
|
|
|
|
void remove(
|
|
elementClass *element);
|
|
|
|
void dumpPoolStats(void);
|
|
|
|
private:
|
|
|
|
AVLElement<elementClass> *tree;
|
|
|
|
Pool *avlElementPool;
|
|
|
|
unsigned insertions;
|
|
unsigned deletions;
|
|
unsigned singleRotations;
|
|
unsigned doubleRotations;
|
|
|
|
friend class AVLElement<elementClass>;
|
|
};
|
|
|
|
|
|
// The AVLElement class would normally be declared in the avl.cpp file, except that because it's
|
|
// a template, it needs to be in the header file. It can only be accessed (including creation and
|
|
// destruction) by the AVLTree friend class.
|
|
|
|
template<class elementClass> class AVLElement {
|
|
|
|
private:
|
|
|
|
AVLElement(void);
|
|
|
|
~AVLElement(void);
|
|
|
|
void initialize(void);
|
|
|
|
void insert(
|
|
AVLTree<elementClass> *intoTree,
|
|
elementClass *element);
|
|
|
|
void remove(
|
|
AVLTree<elementClass> *fromTree);
|
|
|
|
unsigned checkAndReturnDepth(
|
|
unsigned *countedElements);
|
|
|
|
int inTree(void);
|
|
|
|
int operator<=(
|
|
AVLElement<elementClass> *peer);
|
|
|
|
int operator<(
|
|
AVLElement<elementClass> *peer);
|
|
|
|
int operator==(
|
|
AVLElement<elementClass> *peer);
|
|
|
|
int operator>=(
|
|
AVLElement<elementClass> *peer);
|
|
|
|
int operator>(
|
|
AVLElement<elementClass> *peer);
|
|
|
|
|
|
AVLElement<elementClass>
|
|
*findFirstLessThanOrEqualTo(
|
|
elementClass *element);
|
|
|
|
AVLElement<elementClass>
|
|
*findFirstGreaterThan(
|
|
elementClass *element);
|
|
|
|
AVLElement<elementClass>
|
|
*findFirstGreaterThanOrEqualTo(
|
|
elementClass *element);
|
|
|
|
void rightAdded(
|
|
AVLTree<elementClass> *tree);
|
|
|
|
void leftAdded(
|
|
AVLTree<elementClass> *tree);
|
|
|
|
void singleRotate(
|
|
AVLTree<elementClass> *tree,
|
|
AVLElement<elementClass> *child,
|
|
AVLBalance whichSide);
|
|
|
|
void doubleRotate(
|
|
AVLTree<elementClass> *tree,
|
|
AVLElement<elementClass> *child,
|
|
AVLElement<elementClass> *grandchild,
|
|
AVLBalance whichSide);
|
|
|
|
void gotOneShorter(
|
|
AVLTree<elementClass> *tree,
|
|
AVLBalance whichSide);
|
|
|
|
AVLBalance balance;
|
|
|
|
AVLElement<elementClass> *left;
|
|
AVLElement<elementClass> *right;
|
|
AVLElement<elementClass> *parent;
|
|
elementClass *element;
|
|
|
|
friend class AVLTree<elementClass>;
|
|
};
|
|
|
|
template<class elementClass> elementClass *
|
|
AVLTree<elementClass>::findFirstLessThanOrEqualTo(
|
|
elementClass *element)
|
|
{
|
|
assert(element);
|
|
if (!tree)
|
|
return(NULL);
|
|
|
|
AVLElement<elementClass> *avlElement = tree->findFirstLessThanOrEqualTo(element);
|
|
if (avlElement) {
|
|
return(avlElement->element);
|
|
} else {
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
template<class elementClass>
|
|
AVLTree<elementClass>::AVLTree(
|
|
unsigned preallocateSize)
|
|
{
|
|
tree = NULL;
|
|
insertions = deletions = singleRotations = doubleRotations = 0;
|
|
avlElementPool = new Pool(sizeof(AVLElement<elementClass>));
|
|
if (preallocateSize && (NULL != avlElementPool)) {
|
|
avlElementPool->preAllocate(preallocateSize);
|
|
}
|
|
}
|
|
|
|
template<class elementClass> AVLTree<elementClass>::~AVLTree(void)
|
|
{
|
|
assert(tree == NULL);
|
|
|
|
if (NULL != avlElementPool) {
|
|
delete avlElementPool;
|
|
}
|
|
}
|
|
|
|
//****************************************************************************
|
|
//* *
|
|
//* Function: findFirstLessThanOrEqualTo *
|
|
//* *
|
|
//* Syntax: AVLElement * findFirstLessThanOrEqualTo( *
|
|
//* elementClass * element) *
|
|
//* *
|
|
//* Input: elementClass * element: *
|
|
//* A pointer to an element to compare against while searching. *
|
|
//* *
|
|
//* Output: AVLElement *: *
|
|
//* The element in the tree that has a value less than or equal *
|
|
//* to the one specified, or NULL on failure. *
|
|
//* *
|
|
//* Synopsis: This function finds the element in the tree that has a value *
|
|
//* less than or equal to the one specified. *
|
|
//* *
|
|
//****************************************************************************
|
|
template<class elementClass> AVLElement<elementClass> *
|
|
AVLElement<elementClass>::findFirstLessThanOrEqualTo(elementClass * element)
|
|
{
|
|
AVLElement<elementClass> * retVal = NULL;
|
|
|
|
if (*this->element == element) {
|
|
// We have a direct match (equal to). It takes precidence over the
|
|
// "first less than" part.
|
|
return this;
|
|
}
|
|
if (*this->element < element) {
|
|
// The current element is smaller than the one specified.
|
|
// This might be it, but try to find a bigger one.
|
|
if (right != NULL) {
|
|
retVal = right->findFirstLessThanOrEqualTo(element);
|
|
}
|
|
|
|
// If nothing below us (to the right) was found, then we are the
|
|
// next smallest one.
|
|
if (retVal == NULL) {
|
|
return this;
|
|
}
|
|
else {
|
|
return retVal;
|
|
}
|
|
}
|
|
else {
|
|
// The current element is bigger than the one specified.
|
|
// We have to find a smaller one.
|
|
if (left != NULL) {
|
|
return left->findFirstLessThanOrEqualTo(element);
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<class elementClass> elementClass *
|
|
AVLTree<elementClass>::findFirstGreaterThan(
|
|
elementClass *element)
|
|
{
|
|
assert(element);
|
|
if (!tree)
|
|
return(NULL);
|
|
|
|
AVLElement<elementClass> *avlElement = tree->findFirstGreaterThan(element);
|
|
|
|
if (avlElement) {
|
|
return(avlElement->element);
|
|
} else {
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
//****************************************************************************
|
|
//* *
|
|
//* Function: findFirstGreaterThan *
|
|
//* *
|
|
//* Syntax: AVLElement * findFirstGreaterThan(elementClass * element) *
|
|
//* *
|
|
//* Input: elementClass * element: *
|
|
//* A pointer to an element to compare against while searching. *
|
|
//* *
|
|
//* Output: AVLElement *: *
|
|
//* The element in the tree that has a vlaue greater than the *
|
|
//* one specified, or NULL on failure. *
|
|
//* *
|
|
//* Synopsis: This function finds the element in the tree that has a value *
|
|
//* greater than the one specified. *
|
|
//* *
|
|
//****************************************************************************
|
|
template<class elementClass> AVLElement<elementClass> *
|
|
AVLElement<elementClass>::findFirstGreaterThan(elementClass * element)
|
|
{
|
|
AVLElement<elementClass> * retVal = NULL;
|
|
|
|
if (*this->element > element) {
|
|
// The current element is bigger than the one specified.
|
|
// This might be it, but try to find a smaller one.
|
|
if (left != NULL) {
|
|
retVal = left->findFirstGreaterThan(element);
|
|
}
|
|
|
|
// If nothing below us (to the left) was found, then we are the
|
|
// next biggest one.
|
|
if (retVal == NULL) {
|
|
return this;
|
|
}
|
|
else {
|
|
return retVal;
|
|
}
|
|
}
|
|
else {
|
|
// The current element is smaller than (or equal) the one specified.
|
|
// We have to find a bigger one.
|
|
if (right != NULL) {
|
|
return right->findFirstGreaterThan(element);
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<class elementClass> elementClass *
|
|
AVLTree<elementClass>::findFirstGreaterThanOrEqualTo(
|
|
elementClass *element)
|
|
{
|
|
assert(element);
|
|
if (!tree)
|
|
return(NULL);
|
|
|
|
AVLElement<elementClass> *avlElement = tree->findFirstGreaterThanOrEqualTo(element);
|
|
|
|
if (avlElement) {
|
|
return(avlElement->element);
|
|
} else {
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
//****************************************************************************
|
|
//* *
|
|
//* Function: findFirstGreaterThanOrEqualTo *
|
|
//* *
|
|
//* Syntax: AVLElement * findFirstGreaterThanOrEqualTo(elementClass * element)
|
|
//* *
|
|
//* Input: elementClass * element: *
|
|
//* A pointer to an element to compare against while searching. *
|
|
//* *
|
|
//* Output: AVLElement *: *
|
|
//* The element in the tree that has a vlaue greater than or *
|
|
//* equal to the one specified, or NULL on failure. *
|
|
//* *
|
|
//* Synopsis: This function finds the element in the tree that has a value *
|
|
//* greater than or equal to the one specified. *
|
|
//* *
|
|
//****************************************************************************
|
|
template<class elementClass> AVLElement<elementClass> *
|
|
AVLElement<elementClass>::findFirstGreaterThanOrEqualTo(elementClass * element)
|
|
{
|
|
if (*this->element == element) {
|
|
// We have a direct match (equal to). It takes precidence over the
|
|
// "first less than" part.
|
|
return this;
|
|
}
|
|
|
|
AVLElement<elementClass> * retVal = NULL;
|
|
|
|
if (*this->element > element) {
|
|
// The current element is bigger than the one specified.
|
|
// This might be it, but try to find a smaller one.
|
|
if (left != NULL) {
|
|
retVal = left->findFirstGreaterThanOrEqualTo(element);
|
|
}
|
|
|
|
// If nothing below us (to the left) was found, then we are the
|
|
// next biggest one.
|
|
if (retVal == NULL) {
|
|
return this;
|
|
} else {
|
|
return retVal;
|
|
}
|
|
} else {
|
|
// The current element is strictly smaller than the one specified.
|
|
// We have to find a bigger one.
|
|
if (right != NULL) {
|
|
return right->findFirstGreaterThanOrEqualTo(element);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<class elementClass> int
|
|
AVLTree<elementClass>::empty(void)
|
|
{
|
|
assert((tree == NULL) == (insertions == deletions));
|
|
return(tree == NULL);
|
|
}
|
|
|
|
template<class elementClass> unsigned
|
|
AVLTree<elementClass>::size(void)
|
|
{
|
|
assert(insertions >= deletions);
|
|
assert((tree == NULL) == (insertions == deletions));
|
|
return(insertions - deletions);
|
|
}
|
|
|
|
template<class elementClass> elementClass *
|
|
AVLTree<elementClass>::findMin(void)
|
|
{
|
|
if (!tree) {
|
|
return(NULL);
|
|
}
|
|
|
|
AVLElement<elementClass> *candidate = tree;
|
|
while (candidate->left) {
|
|
assert(*candidate->left->element <= candidate->element);
|
|
candidate = candidate->left;
|
|
}
|
|
return(candidate->element);
|
|
}
|
|
|
|
template<class elementClass> elementClass *
|
|
AVLTree<elementClass>::findMax(void)
|
|
{
|
|
if (!tree) {
|
|
return(NULL);
|
|
}
|
|
|
|
AVLElement<elementClass> *candidate = tree;
|
|
while (candidate->right) {
|
|
assert(*candidate->right->element >= candidate->element);
|
|
candidate = candidate->right;
|
|
}
|
|
return(candidate->element);
|
|
}
|
|
|
|
template<class elementClass> void
|
|
AVLTree<elementClass>::check(void)
|
|
{
|
|
AVLElement<elementClass> * currElement = NULL;
|
|
AVLElement<elementClass> * nextElement = NULL;
|
|
AVLElement<elementClass> * oldElement = NULL;
|
|
|
|
unsigned countedElements = 0;
|
|
if (tree) {
|
|
assert(tree->parent == NULL);
|
|
unsigned overallDepth = tree->checkAndReturnDepth(&countedElements);
|
|
}
|
|
assert(insertions-deletions == countedElements);
|
|
|
|
// Check every element in the tree for consistance by verifying that it is in
|
|
// the expected order. If not, it is most likely that the element's operators
|
|
// are not behaving as needed.
|
|
for(currElement = tree; currElement != NULL; currElement = nextElement) {
|
|
// Go left if we can (and have not already been here).
|
|
if (currElement->left && oldElement == currElement->parent) {
|
|
nextElement = currElement->left;
|
|
assert(*nextElement < currElement && "The < operator appears to be broken");
|
|
assert(*currElement > nextElement && "The > operator appears to be broken");
|
|
assert(!(*nextElement == currElement) && "The == operator appears to be broken");
|
|
}
|
|
// Otherwise go right if we can (and have not already been here).
|
|
else if (currElement->right &&
|
|
(oldElement == currElement->left || oldElement == currElement->parent)) {
|
|
nextElement = currElement->right;
|
|
assert(*nextElement > currElement && "The > operator appears to be broken");
|
|
assert(*currElement < nextElement && "The < operator appears to be broken");
|
|
assert(!(*nextElement == currElement) && "The == operator appears to be broken");
|
|
}
|
|
// We are done below us, go up a node.
|
|
else {
|
|
nextElement = currElement->parent;
|
|
}
|
|
|
|
oldElement = currElement;
|
|
assert(*oldElement == currElement && "The == operator appears to be broken");
|
|
}
|
|
}
|
|
|
|
|
|
template<class elementClass>
|
|
AVLElement<elementClass>::AVLElement(void)
|
|
{
|
|
balance = AVLNew;
|
|
left = right = parent = NULL;
|
|
}
|
|
|
|
template<class elementClass>
|
|
AVLElement<elementClass>::~AVLElement(void)
|
|
{
|
|
assert(balance == AVLNew);
|
|
assert(left == NULL && right == NULL && parent == NULL);
|
|
}
|
|
|
|
template<class elementClass> unsigned
|
|
AVLElement<elementClass>::checkAndReturnDepth(
|
|
unsigned *countedElements)
|
|
{
|
|
// We've been inserted and not deleted
|
|
assert(balance != AVLNew);
|
|
|
|
(*countedElements)++;
|
|
|
|
// Assert that the links all match up.
|
|
assert(!left || left->parent == this);
|
|
assert(!right || right->parent == this);
|
|
|
|
// The basic binary tree ordering property applies
|
|
assert(!right || *this <= right);
|
|
assert(!left || *this >= left);
|
|
|
|
// The AVL balance property applies
|
|
unsigned leftDepth;
|
|
if (left) {
|
|
leftDepth = left->checkAndReturnDepth(countedElements);
|
|
} else {
|
|
leftDepth = 0;
|
|
}
|
|
|
|
unsigned rightDepth;
|
|
if (right) {
|
|
rightDepth = right->checkAndReturnDepth(countedElements);
|
|
} else {
|
|
rightDepth = 0;
|
|
}
|
|
|
|
if (leftDepth == rightDepth) {
|
|
assert(balance == AVLBalanced);
|
|
return(leftDepth + 1);
|
|
}
|
|
|
|
if (leftDepth == rightDepth + 1) {
|
|
assert(balance == AVLLeft);
|
|
return(leftDepth + 1);
|
|
}
|
|
|
|
if (leftDepth + 1 == rightDepth) {
|
|
assert(balance == AVLRight);
|
|
return(rightDepth + 1);
|
|
}
|
|
|
|
assert(!"AVL Tree out of balance");
|
|
return(0);
|
|
}
|
|
|
|
template<class elementClass> void
|
|
AVLElement<elementClass>::insert(
|
|
AVLTree<elementClass> *intoTree,
|
|
elementClass *element)
|
|
{
|
|
assert(intoTree);
|
|
assert(left == NULL && right == NULL && parent == NULL);
|
|
|
|
this->element = element;
|
|
assert(this->element);
|
|
|
|
intoTree->insertions++;
|
|
|
|
// Special case the empty tree case.
|
|
if (intoTree->tree == NULL) {
|
|
intoTree->tree = this;
|
|
balance = AVLBalanced;
|
|
// We already know all of the links are NULL, which is correct for this case.
|
|
return;
|
|
}
|
|
|
|
// Find the leaf position at which to do this insertion.
|
|
|
|
AVLElement *currentNode = intoTree->tree;
|
|
AVLElement *previousNode;
|
|
while (currentNode) {
|
|
previousNode = currentNode;
|
|
if (*currentNode < this) {
|
|
currentNode = currentNode->right;
|
|
} else if (*currentNode > this) {
|
|
currentNode = currentNode->left;
|
|
} else {
|
|
// An AVL tree gets all whacky if you try to insert duplicate values.
|
|
assert(!"Trying to insert a duplicate item. Use something other than an AVL tree.");
|
|
}
|
|
}
|
|
|
|
balance = AVLBalanced;
|
|
parent = previousNode;
|
|
assert(parent);
|
|
if (*previousNode <= this) {
|
|
assert(!previousNode->right);
|
|
previousNode->right = this;
|
|
previousNode->rightAdded(intoTree);
|
|
// intoTree->check();
|
|
} else {
|
|
assert(!previousNode->left);
|
|
previousNode->left = this;
|
|
previousNode->leftAdded(intoTree);
|
|
// intoTree->check();
|
|
}
|
|
}
|
|
|
|
template<class elementClass> void
|
|
AVLElement<elementClass>::rightAdded(
|
|
AVLTree<elementClass> *tree)
|
|
{
|
|
//We've just gotten one deeper on our right side.
|
|
assert(balance != AVLNew);
|
|
|
|
if (balance == AVLLeft) {
|
|
balance = AVLBalanced;
|
|
// The depth of the subtree rooted here hasn't changed, we're done
|
|
return;
|
|
}
|
|
if (balance == AVLBalanced) {
|
|
// We've just gotten one deeper, but are still balanced. Update and recurse up the
|
|
// tree.
|
|
balance = AVLRight;
|
|
if (parent) {
|
|
if (parent->right == this) {
|
|
parent->rightAdded(tree);
|
|
} else {
|
|
assert(parent->left == this);
|
|
parent->leftAdded(tree);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
assert(balance == AVLRight);
|
|
// We've just gone to double right (ie, out of balance).
|
|
assert(right);
|
|
if (right->balance == AVLRight) {
|
|
singleRotate(tree,right,AVLRight);
|
|
} else {
|
|
assert(right->balance == AVLLeft); // Else we shouldn't have been AVLRight before the call
|
|
doubleRotate(tree,right,right->left,AVLRight);
|
|
}
|
|
}
|
|
|
|
template<class elementClass> void
|
|
AVLElement<elementClass>::leftAdded(
|
|
AVLTree<elementClass> *tree)
|
|
{
|
|
//We've just gotten one deeper on our right side.
|
|
assert(balance != AVLNew);
|
|
|
|
if (balance == AVLRight) {
|
|
balance = AVLBalanced;
|
|
// The depth of the subtree rooted here hasn't changed, we're done
|
|
return;
|
|
}
|
|
if (balance == AVLBalanced) {
|
|
// We've just gotten one deeper, but are still balanced. Update and recurse up the
|
|
// tree.
|
|
balance = AVLLeft;
|
|
if (parent) {
|
|
if (parent->right == this) {
|
|
parent->rightAdded(tree);
|
|
} else {
|
|
assert(parent->left == this);
|
|
parent->leftAdded(tree);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
assert(balance == AVLLeft);
|
|
// We've just gone to double left (ie, out of balance).
|
|
assert(left);
|
|
if (left->balance == AVLLeft) {
|
|
singleRotate(tree,left,AVLLeft);
|
|
} else {
|
|
assert(left->balance == AVLRight); // Else we shouldn't have been AVLLeft before the call
|
|
doubleRotate(tree,left,left->right,AVLLeft);
|
|
}
|
|
}
|
|
|
|
template<class elementClass> void
|
|
AVLElement<elementClass>::singleRotate(
|
|
AVLTree<elementClass> *tree,
|
|
AVLElement *child,
|
|
AVLBalance whichSide)
|
|
{
|
|
// We're the parent node.
|
|
|
|
assert(tree);
|
|
assert(child);
|
|
assert(whichSide == AVLRight || whichSide == AVLLeft);
|
|
|
|
assert(whichSide != AVLRight || right == child);
|
|
assert(whichSide != AVLLeft || left == child);
|
|
|
|
tree->singleRotations++;
|
|
|
|
// Promote the child to our position in the tree.
|
|
|
|
if (parent) {
|
|
if (parent->left == this) {
|
|
parent->left = child;
|
|
child->parent = parent;
|
|
} else {
|
|
assert(parent->right == this);
|
|
parent->right = child;
|
|
child->parent = parent;
|
|
}
|
|
} else {
|
|
// We're the root of the tree
|
|
assert(tree->tree == this);
|
|
tree->tree = child;
|
|
child->parent = NULL;
|
|
}
|
|
|
|
// Attach the child's light subtree to our heavy side (ie., where the child is attached now)
|
|
// Then, attach us to the child's light subtree
|
|
if (whichSide == AVLRight) {
|
|
right = child->left;
|
|
if (right) {
|
|
right->parent = this;
|
|
}
|
|
|
|
child->left = this;
|
|
parent = child;
|
|
} else {
|
|
left = child->right;
|
|
if (left) {
|
|
left->parent = this;
|
|
}
|
|
|
|
child->right = this;
|
|
parent = child;
|
|
}
|
|
|
|
// Finally, now both our and our (former) child's balance is "balanced"
|
|
balance = AVLBalanced;
|
|
child->balance = AVLBalanced;
|
|
// NB. One of the cases in delete will result in the above balance settings being incorrect. That
|
|
// case fixes up the settings after we return.
|
|
}
|
|
|
|
template<class elementClass> void
|
|
AVLElement<elementClass>::doubleRotate(
|
|
AVLTree<elementClass> *tree,
|
|
AVLElement *child,
|
|
AVLElement *grandchild,
|
|
AVLBalance whichSide)
|
|
{
|
|
assert(tree && child && grandchild);
|
|
assert(whichSide == AVLLeft || whichSide == AVLRight);
|
|
|
|
assert(whichSide != AVLLeft || (left == child && child->balance == AVLRight));
|
|
assert(whichSide != AVLRight || (right == child && child->balance == AVLLeft));
|
|
|
|
assert(child->parent == this);
|
|
assert(grandchild->parent == child);
|
|
|
|
tree->doubleRotations++;
|
|
|
|
// Write down a copy of all of the subtrees; see Knuth v3 p454 for the picture.
|
|
// NOTE: The alpha and delta trees are never moved, so we don't store them.
|
|
AVLElement *beta;
|
|
AVLElement *gamma;
|
|
|
|
if (whichSide == AVLRight) {
|
|
beta = grandchild->left;
|
|
gamma = grandchild->right;
|
|
} else {
|
|
beta = grandchild->right;
|
|
gamma = grandchild->left;
|
|
}
|
|
|
|
// Promote grandchild to our position
|
|
if (parent) {
|
|
if (parent->left == this) {
|
|
parent->left = grandchild;
|
|
} else {
|
|
assert(parent->right == this);
|
|
parent->right = grandchild;
|
|
}
|
|
} else {
|
|
assert(tree->tree == this);
|
|
tree->tree = grandchild;
|
|
}
|
|
grandchild->parent = parent;
|
|
|
|
// Attach the appropriate children to grandchild
|
|
if (whichSide == AVLRight) {
|
|
grandchild->right = child;
|
|
grandchild->left = this;
|
|
} else {
|
|
grandchild->right = this;
|
|
grandchild->left = child;
|
|
}
|
|
parent = grandchild;
|
|
child->parent = grandchild;
|
|
|
|
// Attach beta and gamma to us and child.
|
|
if (whichSide == AVLRight) {
|
|
right = beta;
|
|
if (beta) {
|
|
beta->parent = this;
|
|
}
|
|
child->left = gamma;
|
|
if (gamma) {
|
|
gamma->parent = child;
|
|
}
|
|
} else {
|
|
left = beta;
|
|
if (beta) {
|
|
beta->parent = this;
|
|
}
|
|
child->right = gamma;
|
|
if (gamma) {
|
|
gamma->parent = child;
|
|
}
|
|
}
|
|
|
|
// Now update the balance fields.
|
|
switch (grandchild->balance) {
|
|
case AVLLeft:
|
|
if (whichSide == AVLRight) {
|
|
balance = AVLBalanced;
|
|
child->balance = AVLRight;
|
|
} else {
|
|
balance = AVLRight;
|
|
child->balance = AVLBalanced;
|
|
}
|
|
break;
|
|
|
|
case AVLBalanced:
|
|
balance = AVLBalanced;
|
|
child->balance = AVLBalanced;
|
|
break;
|
|
|
|
case AVLRight:
|
|
if (whichSide == AVLRight) {
|
|
balance = AVLLeft;
|
|
child->balance = AVLBalanced;
|
|
} else {
|
|
balance = AVLBalanced;
|
|
child->balance = AVLLeft;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
assert(!"Bogus balance value");
|
|
}
|
|
grandchild->balance = AVLBalanced;
|
|
}
|
|
|
|
template<class elementClass> void
|
|
AVLElement<elementClass>::remove(
|
|
AVLTree<elementClass> *fromTree)
|
|
{
|
|
assert(fromTree);
|
|
assert(balance == AVLRight || balance == AVLLeft || balance == AVLBalanced);
|
|
|
|
fromTree->deletions++;
|
|
|
|
if (left == NULL) {
|
|
// The right child either doesn't exist or is a leaf (because of the AVL balance property)
|
|
assert((!right && balance == AVLBalanced) ||
|
|
(balance == AVLRight && right->balance == AVLBalanced && right->right == NULL && right->left == NULL));
|
|
if (right) {
|
|
right->parent = parent;
|
|
}
|
|
if (parent) {
|
|
if (parent->left == this) {
|
|
parent->left = right;
|
|
parent->gotOneShorter(fromTree,AVLLeft);
|
|
} else {
|
|
assert(parent->right == this);
|
|
parent->right = right;
|
|
parent->gotOneShorter(fromTree,AVLRight);
|
|
}
|
|
} else {
|
|
assert(fromTree->tree == this);
|
|
fromTree->tree = right;
|
|
}
|
|
} else if (right == NULL) {
|
|
// The left child must be a left because of the AVL balance property
|
|
assert(left && balance == AVLLeft && left->balance == AVLBalanced && left->right == NULL && left->left == NULL);
|
|
left->parent = parent;
|
|
if (parent) {
|
|
if (parent->left == this) {
|
|
parent->left = left;
|
|
parent->gotOneShorter(fromTree,AVLLeft);
|
|
} else {
|
|
assert(parent->right == this);
|
|
parent->right = left;
|
|
parent->gotOneShorter(fromTree,AVLRight);
|
|
}
|
|
} else {
|
|
assert(fromTree->tree == this);
|
|
fromTree->tree = left;
|
|
}
|
|
} else {
|
|
// Find the symmetric successor and promote it. The symmetric successor is the smallest element in the right
|
|
// subtree; it's found by following all left links in the right subtree until we find a node with no left link.
|
|
// That node may be promoted to the place of this without corrupting the binary tree ordering properties. (We could
|
|
// just as easily use the symmetric predecessor by finding the largest element in the right subtree, but there's
|
|
// no point.)
|
|
|
|
AVLElement *successorCandidate = right;
|
|
while (successorCandidate->left) {
|
|
successorCandidate = successorCandidate->left;
|
|
}
|
|
|
|
AVLElement *shorterRoot;
|
|
AVLBalance shorterSide;
|
|
if (successorCandidate->parent->left == successorCandidate) {
|
|
// We need to promote the successor's child (if any) to its position, then
|
|
// promote it to our position.
|
|
shorterRoot = successorCandidate->parent;
|
|
shorterSide = AVLLeft;
|
|
successorCandidate->parent->left = successorCandidate->right;
|
|
if (successorCandidate->right) {
|
|
successorCandidate->right->parent = successorCandidate->parent;
|
|
}
|
|
|
|
successorCandidate->right = right;
|
|
successorCandidate->left = left;
|
|
successorCandidate->balance = balance;
|
|
successorCandidate->right->parent = successorCandidate;
|
|
successorCandidate->left->parent = successorCandidate;
|
|
if (parent) {
|
|
if (parent->left == this) {
|
|
parent->left = successorCandidate;
|
|
} else {
|
|
assert(parent->right == this);
|
|
parent->right = successorCandidate;
|
|
}
|
|
} else {
|
|
assert(fromTree->tree == this);
|
|
fromTree->tree = successorCandidate;
|
|
}
|
|
successorCandidate->parent = parent;
|
|
} else {
|
|
// The successor was our child, just directly promote it.
|
|
assert(successorCandidate->parent == this);
|
|
if (parent) {
|
|
if (parent->right == this) {
|
|
parent->right = successorCandidate;
|
|
} else {
|
|
assert(parent->left == this);
|
|
parent->left = successorCandidate;
|
|
}
|
|
} else {
|
|
assert(fromTree->tree == this);
|
|
fromTree->tree = successorCandidate;
|
|
}
|
|
successorCandidate->parent = parent;
|
|
successorCandidate->left = left;
|
|
if (left) {
|
|
left->parent = successorCandidate;
|
|
}
|
|
// We just made our right subtree shorter.
|
|
successorCandidate->balance = balance;
|
|
shorterRoot = successorCandidate;
|
|
shorterSide = AVLRight;
|
|
}
|
|
if (shorterRoot) {
|
|
shorterRoot->gotOneShorter(fromTree,shorterSide);
|
|
}
|
|
}
|
|
|
|
balance = AVLNew;
|
|
left = right = parent = NULL;
|
|
element = NULL;
|
|
// fromTree->check();
|
|
}
|
|
|
|
template<class elementClass> void
|
|
AVLElement<elementClass>::gotOneShorter(
|
|
AVLTree<elementClass> *tree,
|
|
AVLBalance whichSide)
|
|
|
|
{
|
|
assert(whichSide == AVLLeft || whichSide == AVLRight);
|
|
|
|
if (balance == AVLBalanced) {
|
|
// We've just shrunk one subttree, but our depth has stayed the same.
|
|
// Reset our balance indicator and punt.
|
|
if (whichSide == AVLRight) {
|
|
balance = AVLLeft;
|
|
} else {
|
|
balance = AVLRight;
|
|
}
|
|
return;
|
|
} else if (balance == whichSide) {
|
|
// We just shrunk our heavy side; set our balance to neutral and recurse up the tree
|
|
balance = AVLBalanced;
|
|
if (parent) {
|
|
if (parent->right == this) {
|
|
parent->gotOneShorter(tree,AVLRight);
|
|
} else {
|
|
assert(parent->left == this);
|
|
parent->gotOneShorter(tree,AVLLeft);
|
|
}
|
|
} // else we were the root; we're done
|
|
return;
|
|
} else {
|
|
// We've just gone out of balance. Figure out a rotation to do. This is almost like having added a
|
|
// node to the opposide side, except that the opposite side might be balanced.
|
|
AVLBalance heavySide;
|
|
AVLElement *heavyChild;
|
|
AVLElement *replacement;
|
|
if (whichSide == AVLRight) {
|
|
heavySide = AVLLeft;
|
|
heavyChild = left;
|
|
} else {
|
|
heavySide = AVLRight;
|
|
heavyChild = right;
|
|
}
|
|
assert(heavyChild);
|
|
if (heavyChild->balance == heavySide) {
|
|
// Typical single rotation case
|
|
singleRotate(tree,heavyChild,heavySide);
|
|
replacement = heavyChild;
|
|
} else if (heavyChild->balance == whichSide) {
|
|
// Typical double rotation case
|
|
AVLElement *grandchild;
|
|
if (heavySide == AVLRight) {
|
|
grandchild = heavyChild->left;
|
|
} else {
|
|
grandchild = heavyChild->right;
|
|
}
|
|
doubleRotate(tree,heavyChild,grandchild,heavySide);
|
|
replacement = grandchild;
|
|
} else {
|
|
assert(heavyChild->balance == AVLBalanced);
|
|
singleRotate(tree,heavyChild,heavySide);
|
|
// singleRotate has incorrectly set the balances; reset them
|
|
balance = heavySide;
|
|
heavyChild->balance = whichSide;
|
|
// Overall depth hasn't changed; we're done.
|
|
return;
|
|
}
|
|
|
|
// NB: we have now changed position in the tree, so parent, right & left have changed!
|
|
if (!replacement->parent) {
|
|
// We just promoted our replacement to the root; we be done
|
|
return;
|
|
}
|
|
if (replacement->parent->right == replacement) {
|
|
replacement->parent->gotOneShorter(tree,AVLRight);
|
|
} else {
|
|
assert(replacement->parent->left == replacement);
|
|
replacement->parent->gotOneShorter(tree,AVLLeft);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
template<class elementClass> int
|
|
AVLElement<elementClass>::inTree(void)
|
|
{
|
|
return(balance != AVLNew);
|
|
}
|
|
|
|
template <class elementClass> int
|
|
AVLElement<elementClass>::operator<=(
|
|
AVLElement<elementClass> *peer)
|
|
{
|
|
return(*element <= peer->element);
|
|
}
|
|
|
|
template <class elementClass> int
|
|
AVLElement<elementClass>::operator<(
|
|
AVLElement<elementClass> *peer)
|
|
{
|
|
return(*element < peer->element);
|
|
}
|
|
|
|
template <class elementClass> int
|
|
AVLElement<elementClass>::operator==(
|
|
AVLElement<elementClass> *peer)
|
|
{
|
|
return(*element == peer->element);
|
|
}
|
|
|
|
template <class elementClass> int
|
|
AVLElement<elementClass>::operator>=(
|
|
AVLElement<elementClass> *peer)
|
|
{
|
|
return(*element >= peer->element);
|
|
}
|
|
|
|
template <class elementClass> int
|
|
AVLElement<elementClass>::operator>(
|
|
AVLElement<elementClass> *peer)
|
|
{
|
|
return(*element > peer->element);
|
|
}
|
|
|
|
template <class elementClass> BOOLEAN
|
|
AVLTree<elementClass>::insert(
|
|
elementClass *element)
|
|
{
|
|
if (NULL == avlElementPool) {
|
|
return FALSE;
|
|
}
|
|
|
|
assert(element);
|
|
AVLElement<elementClass> *avlElement = (AVLElement<elementClass> *)avlElementPool->allocate();
|
|
if (NULL == avlElement) {
|
|
return FALSE;
|
|
}
|
|
|
|
avlElement->initialize();
|
|
avlElement->insert(this,element);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
template <class elementClass> void
|
|
AVLTree<elementClass>::remove(
|
|
elementClass *element)
|
|
{
|
|
assert(element);
|
|
AVLElement<elementClass> *candidate = tree->findFirstLessThanOrEqualTo(element);
|
|
assert(candidate && *candidate->element == element);
|
|
candidate->remove(this);
|
|
assert(avlElementPool); // if this isn't true, then we could never have had a successful insert
|
|
avlElementPool->free((void *)candidate);
|
|
}
|
|
|
|
template <class elementClass> void
|
|
AVLElement<elementClass>::initialize(void)
|
|
{
|
|
balance = AVLNew;
|
|
left = right = parent = NULL;
|
|
element = NULL;
|
|
}
|
|
|
|
template <class elementClass> void
|
|
AVLTree<elementClass>::dumpPoolStats(void)
|
|
{
|
|
if (NULL == avlElementPool) {
|
|
DbgPrint("Unable to allocate avlElementPool; this AVL tree is essentially useless\n");
|
|
} else {
|
|
DbgPrint("AVLTree AVLElement pool: %d allocations, %d frees, %d news, objectSize %d\n",
|
|
avlElementPool->numAllocations(),
|
|
avlElementPool->numFrees(),
|
|
avlElementPool->numNews(),
|
|
avlElementPool->getObjectSize());
|
|
}
|
|
}
|