/*==========================================================================
_____ .__ .__
/ \ ____ _____| |__ __ __| | _____
/ \ / \_/ __ \ / ___/ | \| | \ | \__ \
/ Y \ ___/ \___ \| Y \ | / |__/ __ \_
\____|__ /\___ >____ >___| /____/|____(____ /
\/ \/ \/ \/ \/
_________ ____.____ ___________
/ _ \ \ / /| | \__ ___/______ ____ ____
/ /_\ \ Y / | | | | \_ __ \_/ __ \_/ __ \
/ | \ / | |___ | | | | \/\ ___/\ ___/
\____|__ /\___/ |_______ \ |____| |__| \___ >\___ >
\/ \/ \/ \/
with thanks to -
Greig McLachlan of http://www.learntoprogram.com
for providing a clean implementation of Insert which I used as a starting point
Jason F Boxall of CSC330
who posted his assignment on the web, I double checked my Remove implementation against his.
R Levow of http://www.cse.fau.edu/~roy/cop3530.98f/prog5-BSTIterator.html
who posted an algorithm for creating binary tree iterators
http://meshula.artistnation.com
2002
The template is free for use, no warrantee or suitability for any particular
purpose is expressed or implied. Verify that it works the way you expect before you
incorporate it into your own project.
public interface -
AVL();
~AVL();
bool Insert(KeyType key, ItemType item);
bool Remove(KeyType key);
bool Find(KeyType key, ItemType& item);
short GetDepth()
Iterator(Iterator*)
Iterator(AVL*)
~Iterator()
// all return true for success, false for failure or end of tree
bool GetFirst(KeyType& key, ItemType& item)
bool GetNext(KeyType& key, ItemType& item)
bool GetCurrent(KeyType& key, ItemType& item)
bool Find(KeyType key, ItemType& item)
==========================================================================*/
/*--------------------------------------------------------------------------------------------
___ ___ _ _ _ _
/ \ \ / / | __| | ___ ___| | __ _ _ __ __ _| |_(_) ___ _ __
/ _ \ \ / /| | / _` |/ _ \/ __| |/ _` | '__/ _` | __| |/ _ \| '_ \
/ ___ \ V / | |___ | (_| | __/ (__| | (_| | | | (_| | |_| | (_) | | | |
/_/ \_\_/ |_____| \__,_|\___|\___|_|\__,_|_| \__,_|\__|_|\___/|_| |_|
--------------------------------------------------------------------------------------------*/
template<class KeyType, class ItemType>
class AVL
{
protected:
template<class KeyType, class ItemType>
class AVLNode
{
public:
AVLNode(KeyType key, ItemType item) :
m_Balance(0), m_Depth(0),
m_Key(key), m_Data(item),
m_pLeft(0), m_pRight(0)
{
}
short m_Balance;
short m_Depth;
KeyType m_Key;
ItemType m_Data;
AVLNode* m_pLeft;
AVLNode* m_pRight;
};
AVLNode<KeyType, ItemType>* m_pRoot;
public:
/*------------------------------------------------------------------------
_ _ _ _ _ __
_ __ _ _| |__ | (_) ___ (_)_ __ | |_ ___ _ __ / _| __ _ ___ ___
| '_ \| | | | '_ \| | |/ __| | | '_ \| __/ _ \ '__| |_ / _` |/ __/ _ \
| |_) | |_| | |_) | | | (__ | | | | | || __/ | | _| (_| | (_| __/
| .__/ \__,_|_.__/|_|_|\___| |_|_| |_|\__\___|_| |_| \__,_|\___\___|
|_| */
AVL() : m_pRoot(0) { }
~AVL() { }
void Insert(KeyType key, ItemType item);
void Remove(KeyType key);
bool Find (KeyType key, ItemType& item);
short GetDepth() const { return (m_pRoot ? m_pRoot->m_Depth : 0); }
/*------------------------------------------------------------------------
_ _ _
(_) |_ ___ _ __ __ _| |_ ___ _ __
| | __/ _ \ '__/ _` | __/ _ \| '__|
| | || __/ | | (_| | || (_) | |
|_|\__\___|_| \__,_|\__\___/|_|
*/
template<class KeyType, class ItemType>
class Iterator
{
#define kMaxAVLDepth 32
public:
Iterator(Iterator* pCopyMe) :
mpAVL(pCopyMe->mpAVL), mpCurr(pCopyMe->mpCurr)
{
mTraversalStackIndex = pCopyMe->mTraversalStackIndex;
for (int i = 0; i < mTraversalStackIndex; ++i)
mTraversalStack[i] = pCopyMe->mTraversalStack[i];
}
Iterator(AVL<KeyType, ItemType>* pTree) : mpAVL(pTree)
{
KeyType key;
ItemType item;
GetFirst(key, item);
}
~Iterator() { }
bool GetCurrent(KeyType& key, ItemType& item)
{
if (mpCurr)
{
key = mpCurr->m_Key;
item = mpCurr->m_Data;
return true;
}
else
return false;
}
// returns false if the tree is empty
bool GetFirst (KeyType& key, ItemType& item)
{
mTraversalStackIndex = 0;
if (!mpAVL->m_pRoot)
{
mpCurr = 0;
item = 0;
return false;
}
else
{
AVLNode<ItemType, KeyType>* pCurr = mpAVL->m_pRoot;
AVLNode<ItemType, KeyType>* pPrev = pCurr;
while (pCurr)
{
pPrev = pCurr;
if (pCurr->m_pLeft)
mTraversalStack[mTraversalStackIndex++] = pCurr;
pCurr = pCurr->m_pLeft;
}
mpCurr = pPrev;
key = mpCurr->m_Key;
item = mpCurr->m_Data;
return true;
}
}
bool GetNext (KeyType& key, ItemType& item)
{
if (!mpCurr) // already done?
{
item = 0;
return false;
}
else
{
AVLNode<KeyType, ItemType>* pCurr = mpCurr->m_pRight; // start looking to the right
while (true) // this while forces a traversal as far left as possible
{
if (pCurr) // if we have a pcurr, push it and go left, and repeat.
{
mTraversalStack[mTraversalStackIndex++] = pCurr;
pCurr = pCurr->m_pLeft;
}
else // backtrack
{
if (mTraversalStackIndex > 0)
{
AVLNode<KeyType, ItemType>* pCandidate = mTraversalStack[--mTraversalStackIndex];
// did we backtrack up a right branch?
if (mpCurr == pCandidate->m_pRight)
{
// if there is a parent, return the parent.
if (mTraversalStackIndex > 0)
{
mpCurr = mTraversalStack[--mTraversalStackIndex];
key = mpCurr->m_Key;
item = mpCurr->m_Data;
return true;
}
else // if up a right branch, and no parent, traversal finished
{
mpCurr = 0;
item = 0;
return false;
}
}
else // up a left branch, done.
{
mpCurr = pCandidate;
key = mpCurr->m_Key;
item = mpCurr->m_Data;
return true;
}
}
else // totally done
{
mpCurr = 0;
item = 0;
return false;
}
}
}
}
}
bool Find (KeyType key, ItemType& item)
{
AVLNode<KeyType, ItemType>* pCurr = mpAVL->m_pRoot;
mTraversalStackIndex = 0;
while (true)
{
AVLNode<KeyType, ItemType>* pPushMe = pCurr;
if (pCurr->m_Key == key) // already done?
{
mpCurr = pCurr;
item = mpCurr->m_Data;
return true;
}
if (pCurr->m_Key > key)
pCurr = pCurr->m_pLeft;
else
pCurr = pCurr->m_pRight;
if (pCurr) // maintain the stack so that GetNext will work.
{
mTraversalStack[mTraversalStackIndex++] = pPushMe;
}
else // couldn't find it.
{
mpCurr = 0;
mTraversalStackIndex = 0;
return false;
}
}
return true;
}
protected:
AVL* mpAVL;
AVLNode<KeyType, ItemType>* mTraversalStack[kMaxAVLDepth];
short mTraversalStackIndex;
AVLNode<KeyType, ItemType>* mpCurr; // for iteration
};
friend class AVL::Iterator<KeyType, ItemType>;
protected:
void _Insert (KeyType key, ItemType item, AVLNode<KeyType, ItemType>*& root);
void _Remove (AVLNode<KeyType, ItemType>*& root, KeyType key, bool& delOK);
void _RemoveBothChildren (AVLNode<KeyType, ItemType>*& root, AVLNode<KeyType, ItemType>*& curr, bool& delOK);
bool _Find (KeyType key, ItemType& item, AVLNode<KeyType, ItemType>* root);
void ComputeBalance (AVLNode<KeyType, ItemType>* root);
void Balance (AVLNode<KeyType, ItemType>*& root);
void BalanceRight (AVLNode<KeyType, ItemType>*& root);
void BalanceLeft (AVLNode<KeyType, ItemType>*& root);
void RotateLeft (AVLNode<KeyType, ItemType>*& root);
void RotateRight (AVLNode<KeyType, ItemType>*& root);
};
/*--------------------------------------------------------------------------------------------
_ _ _
(_)_ __ ___ ___ _ __| |_(_) ___ _ __
| | '_ \/ __|/ _ \ '__| __| |/ _ \| '_ \
| | | | \__ \ __/ | | |_| | (_) | | | |
|_|_| |_|___/\___|_| \__|_|\___/|_| |_|
--------------------------------------------------------------------------------------------*/
template<class KeyType, class ItemType>
void AVL<KeyType,ItemType>::Insert(KeyType key, ItemType item)
{
if (m_pRoot == 0)
{
m_pRoot = new AVLNode<KeyType, ItemType>(key, item);
}
else
_Insert(key, item, m_pRoot);
}
template<class KeyType, class ItemType>
void AVL<KeyType, ItemType>::_Insert(KeyType key, ItemType item, AVLNode<KeyType, ItemType>*& root)
{
if (key < root->m_Key)
{
if (root->m_pLeft)
_Insert(key, item, root->m_pLeft);
else
root->m_pLeft = new AVLNode<KeyType, ItemType>(key, item);
}
else if (key > root->m_Key)
{
if (root->m_pRight)
_Insert(key, item, root->m_pRight);
else
root->m_pRight = new AVLNode<KeyType, ItemType>(key, item);
}
else
{
// error - can't have duplicate keys.
// if duplicate keys are okay, change key < to key <= above
}
ComputeBalance(root);
Balance(root);
}
/*--------------------------------------------------------------------------------------------
_
_ __ ___ _ __ ___ _____ ____ _| |
| '__/ _ \ '_ ` _ \ / _ \ \ / / _` | |
| | | __/ | | | | | (_) \ V / (_| | |
|_| \___|_| |_| |_|\___/ \_/ \__,_|_|
--------------------------------------------------------------------------------------------*/
template<class KeyType, class ItemType>
void AVL<KeyType, ItemType>::Remove(KeyType key)
{
bool delOK = false;
_Remove(m_pRoot, key, delOK);
}
template<class KeyType, class ItemType>
void AVL<KeyType, ItemType>::_Remove(AVLNode<KeyType, ItemType>*& root, KeyType key, bool& delOK)
{
if (!root)
{
delOK = false;
}
else if (root->m_Key > key) // go to left subtree
{
_Remove(root->m_pLeft, key, delOK);
if (delOK)
{
ComputeBalance(root);
BalanceRight(root);
}
}
else if (root->m_Key < key) // go to right subtree
{
_Remove(root->m_pRight, key, delOK);
if (delOK)
{
ComputeBalance(root);
BalanceLeft(root);
}
}
else // node found!
{
AVLNode<KeyType, ItemType>* pMe = root;
if (!root->m_pRight)
{
root = root->m_pLeft;
delOK = true;
delete pMe;
}
else if (!root->m_pLeft)
{
root = root->m_pRight;
delOK = true;
delete pMe;
}
else
{
_RemoveBothChildren(root, root->m_pLeft, delOK);
if (delOK)
{
ComputeBalance(root);
Balance(root);
}
delOK = true;
}
}
}
template<class KeyType, class ItemType>
void AVL<KeyType, ItemType>::_RemoveBothChildren(AVLNode<KeyType, ItemType>*& root, AVLNode<KeyType, ItemType>*& curr, bool& delOK)
{
if (!curr->m_pRight)
{
root->m_Key = curr->m_Key;
root->m_Data = curr->m_Data;
AVLNode<KeyType, ItemType>* pMe = curr;
curr = curr->m_pLeft;
delete pMe;
delOK = true;
}
else
{
_RemoveBothChildren(root, curr->m_pRight, delOK);
if (delOK)
{
ComputeBalance(root);
Balance(root);
}
}
}
/*--------------------------------------------------------------------------------------------
_ _
___ ___ __ _ _ __ ___| |__ (_)_ __ __ _
/ __|/ _ \/ _` | '__/ __| '_ \| | '_ \ / _` |
\__ \ __/ (_| | | | (__| | | | | | | | (_| |
|___/\___|\__,_|_| \___|_| |_|_|_| |_|\__, |
|___/
--------------------------------------------------------------------------------------------*/
template<class KeyType, class ItemType>
bool AVL<KeyType, ItemType>::Find(KeyType key, ItemType& item)
{
return _Find(key, item, m_pRoot);
}
template<class KeyType, class ItemType>
bool AVL<KeyType, ItemType>::_Find(KeyType key, ItemType& item, AVLNode<KeyType, ItemType>* root)
{
if (root)
{
if (root->m_Key == key)
{
item = root->m_Data;
return true;
}
if (key < root->m_Key)
return _Find(key, item, root->m_pLeft);
else
return _Find(key, item, root->m_pRight);
}
else
{
return false;
}
}
/*--------------------------------------------------------------------------------------------
_ _ _
| |__ __ _| | __ _ _ __ ___(_)_ __ __ _
| '_ \ / _` | |/ _` | '_ \ / __| | '_ \ / _` |
| |_) | (_| | | (_| | | | | (__| | | | | (_| |
|_.__/ \__,_|_|\__,_|_| |_|\___|_|_| |_|\__, |
|___/
--------------------------------------------------------------------------------------------*/
template<class KeyType, class ItemType>
void AVL<KeyType, ItemType>::ComputeBalance(AVLNode<KeyType, ItemType>* root)
{
if (root)
{
short leftDepth = root->m_pLeft ? root->m_pLeft->m_Depth : 0;
short rightDepth = root->m_pRight ? root->m_pRight->m_Depth : 0;
root->m_Depth = 1 + ((leftDepth > rightDepth) ? leftDepth : rightDepth);
root->m_Balance = rightDepth - leftDepth;
}
}
template<class KeyType, class ItemType>
void AVL<KeyType, ItemType>::Balance(AVLNode<KeyType, ItemType>*& root)
{
// AVL trees have the property that no branch is more than 1 longer than its sibling
if (root->m_Balance > 1)
BalanceRight(root);
if (root->m_Balance < -1)
BalanceLeft(root);
}
template<class KeyType, class ItemType>
void AVL<KeyType, ItemType>::BalanceRight(AVLNode<KeyType, ItemType>*& root)
{
if (root->m_pRight)
{
if (root->m_pRight->m_Balance > 0)
{
RotateLeft(root);
}
else if (root->m_pRight->m_Balance < 0)
{
RotateRight(root->m_pRight);
RotateLeft(root);
}
}
}
template<class KeyType, class ItemType>
void AVL<KeyType, ItemType>::BalanceLeft(AVLNode<KeyType, ItemType>*& root)
{
if (root->m_pLeft)
{
if (root->m_pLeft->m_Balance < 0)
{
RotateRight(root);
}
else if (root->m_pLeft->m_Balance > 0)
{
RotateLeft(root->m_pLeft);
RotateRight(root);
}
}
}
template<class KeyType, class ItemType>
void AVL<KeyType, ItemType>::RotateLeft(AVLNode<KeyType, ItemType>*& root)
{
AVLNode<KeyType, ItemType>* pTemp = root;
root = root->m_pRight;
pTemp->m_pRight = root->m_pLeft;
root->m_pLeft = pTemp;
ComputeBalance(root->m_pLeft);
ComputeBalance(root->m_pRight);
ComputeBalance(root);
}
template<class KeyType, class ItemType>
void AVL<KeyType, ItemType>::RotateRight(AVLNode<KeyType, ItemType>*& root)
{
AVLNode<KeyType, ItemType>* pTemp = root;
root = root->m_pLeft;
pTemp->m_pLeft = root->m_pRight;
root->m_pRight = pTemp;
ComputeBalance(root->m_pLeft);
ComputeBalance(root->m_pRight);
ComputeBalance(root);
}
|