From e0f43e3e843b15d2a90e6ac1c7d0800b7117fca7 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 28 Jun 2003 15:49:33 +0000 Subject: [PATCH] The beginning of an AVL tree based map implementation. Well, the tree part is complete, the interface needs work. Unfortunately our ancient compiler chokes on this (`Internal Compiler Error'). I got around the problem by restructuring parts of the code once, but now I'm stuck -- no idea what I could change. So, there won't be AVLTree{Map,Set} until we have a working compiler. :-( git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3712 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/util/AVLTreeMap.h | 1442 ++++++++++++++++++++++ 1 file changed, 1442 insertions(+) create mode 100644 headers/private/kernel/util/AVLTreeMap.h diff --git a/headers/private/kernel/util/AVLTreeMap.h b/headers/private/kernel/util/AVLTreeMap.h new file mode 100644 index 0000000000..4f3703264f --- /dev/null +++ b/headers/private/kernel/util/AVLTreeMap.h @@ -0,0 +1,1442 @@ +// AVLTreeMap.h +// +// Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// Except as contained in this notice, the name of a copyright holder shall +// not be used in advertising or otherwise to promote the sale, use or other +// dealings in this Software without prior written authorization of the +// copyright holder. + +#ifndef _AVL_TREE_MAP_H +#define _AVL_TREE_MAP_H + +#include + +#include + +#include "MallocFreeAllocator.h" + +// maximal height of a tree +static const int kMaxAVLTreeHeight = 32; + +// strategies +namespace AVLTreeMapStrategy { + // key orders + template class Ascending; + template class Descending; + + //! Automatic node strategy (works like STL containers do) + template , + template class Allocator = MallocFreeAllocator> + class Auto; + + //! User managed node strategy (user is responsible for node allocation/deallocation) +// template +// class User; + +// NodeStrategy::Node must implement this interface. +// struct Node { +// Node *parent; +// Node *left; +// Node *right; +// int balance_factor; +// }; +} + +template class AVLTreeMapIterator; +template class AVLTreeMapEntry; +template class AVLTreeMapEntryPointer; + +// for convenience +#define _AVL_TREE_MAP_TEMPLATE_LIST template +#define _AVL_TREE_MAP_CLASS_NAME AVLTreeMap + +// AVLTreeMap +template > +class AVLTreeMap { +private: + typedef typename NodeStrategy::Node Node; + typedef _AVL_TREE_MAP_CLASS_NAME Class; + typedef AVLTreeMapEntry Entry; + +public: + class Entry; + class Iterator; + class ConstIterator; + +public: + AVLTreeMap(); + ~AVLTreeMap(); + + inline int Count() const { return fNodeCount; } + inline bool IsEmpty() const { return (fNodeCount == 0); } + void MakeEmpty(); + + inline Iterator Begin() { return ++Iterator(this, NULL); } + inline ConstIterator Begin() const { return ++ConstIterator(this, NULL); } + inline Iterator End() { return Iterator(this, NULL); } + inline ConstIterator End() const { return ConstIterator(this, NULL); } + inline Iterator Null() { return Iterator(this, NULL); } + inline ConstIterator Null() const { return ConstIterator(this, NULL); } + + Iterator Find(const Key &key); + Iterator FindClose(const Key &key, bool less); + + status_t Insert(const Key &key, const Value &value, + Iterator &iterator = NULL); + status_t Remove(const Key &key); + Iterator Erase(const Iterator &iterator); + + // debugging + int Check(Node *node = NULL, int level = 0, bool levelsOnly = false) const; + +protected: + enum { + NOT_FOUND = -3, + DUPLICATE = -2, + NO_MEMORY = -1, + OK = 0, + HEIGHT_CHANGED = 1, + + LEFT = -1, + BALANCED = 0, + RIGHT = 1, + }; + + // rotations + void _RotateRight(Node **nodeP); + void _RotateLeft(Node **nodeP); + + // insert + int _BalanceInsertLeft(Node **node); + int _BalanceInsertRight(Node **node); + int _Insert(const Key &key, const Value &value, Node **node, + Iterator *iterator); + + // remove + int _BalanceRemoveLeft(Node **node); + int _BalanceRemoveRight(Node **node); + int _RemoveRightMostChild(Node **node, Node **foundNode); + int _Remove(const Key &key, Node **node); + int _Remove(Node *node); + + void _FreeTree(Node *node); + + // debugging + void _DumpNode(Node *node) const; + + // strategy shortcuts + inline Node *Allocate(const Key &key, const Value &value); + inline void Free(Node *node); + inline Key &GetKey(Node *node) const; + inline Value &GetValue(Node *node) const; + inline int Compare(const Key &a, const Key &b); + +protected: + friend class Entry; + friend class Iterator; + friend class ConstIterator; + friend AVLTreeMapIterator; + friend AVLTreeMapIterator; + + Node *fRoot; + int fNodeCount; + NodeStrategy fStrategy; + + // Iterator + class Iterator : public AVLTreeMapIterator<_AVL_TREE_MAP_CLASS_NAME> { + private: + typedef AVLTreeMapIterator<_AVL_TREE_MAP_CLASS_NAME> SuperClass; + + public: + inline Iterator(); + inline Iterator(const Iterator &other); + + inline Iterator &operator++(); + inline Iterator operator++(int); + inline Iterator &operator--(); + inline Iterator operator--(int); + inline Iterator &operator=(Iterator &other); + + private: + inline Iterator(_AVL_TREE_MAP_CLASS_NAME *parent, Node *node = NULL); + + friend class _AVL_TREE_MAP_CLASS_NAME; + }; + + // ConstIterator + class ConstIterator + : public AVLTreeMapIterator { + private: + typedef AVLTreeMapIterator SuperClass; + + public: + inline ConstIterator(); + inline ConstIterator(const ConstIterator &other); + inline ConstIterator(const Iterator &other); + + inline ConstIterator &operator++(); + inline ConstIterator operator++(int); + inline ConstIterator &operator--(); + inline ConstIterator operator--(int); + inline ConstIterator &operator=(ConstIterator &other); + inline ConstIterator &operator=(Iterator &other); + + private: + inline ConstIterator(const _AVL_TREE_MAP_CLASS_NAME *parent, + Node *node = NULL); + + friend class _AVL_TREE_MAP_CLASS_NAME; + }; +}; + + +// AVLTreeMapEntry +template +class AVLTreeMapEntry { +public: + AVLTreeMapEntry() + : fParent(NULL), fNode(NULL) {} + AVLTreeMapEntry(const AVLTreeMapEntry &other) + : fParent(other.fParent), fNode(other.fNode) {} + + inline const Parent::Key &Key() const + { return fParent->GetKey(fNode); } + inline const Parent::Value &Value() const + { return fParent->GetValue(fNode); } + +private: + AVLTreeMapEntry(const Parent *parent, Parent::Node *node) + : fParent(parent), fNode(node) {} + +private: + friend class AVLTreeMapEntryPointer; + friend class AVLTreeMapIterator; + friend class AVLTreeMapIterator; + + const Parent *fParent; + Parent::Node *fNode; +}; + +// AVLTreeMapEntryPointer +template +class AVLTreeMapEntryPointer { +public: + inline const Entry *operator->() const + { + return &fEntry; + } + +private: + AVLTreeMapEntryPointer(const Parent *parent, Parent::Node *node) + : fEntry(parent, node) {} + + AVLTreeMapEntryPointer(const AVLTreeMapEntryPointer &); + AVLTreeMapEntryPointer &operator=(const AVLTreeMapEntryPointer &); + +private: + friend class AVLTreeMapIterator; + friend class AVLTreeMapIterator; + + AVLTreeMapEntry fEntry; +}; + +// AVLTreeMapIterator +template +class AVLTreeMapIterator { +private: + typedef AVLTreeMapIterator Iterator; + typedef typename Parent::Node Node; + typedef typename Parent::Entry Entry; + typedef AVLTreeMapEntryPointer EntryPointer; + +public: + inline bool operator==(const Iterator &other) const + { + return (fParent == other.fParent && fCurrent == other.fCurrent); + } + + inline bool operator!=(const Iterator &other) const + { + return !(*this == other); + } + + inline const Entry operator*() const + { + return Entry(fParent, fCurrent); + } + + inline const EntryPointer operator->() const + { + return EntryPointer(fParent, fCurrent); + } + +protected: + inline AVLTreeMapIterator() + : fParent(NULL), + fCurrent(NULL) + { + } + + inline AVLTreeMapIterator(const Iterator &other) + : fParent(other.fParent), + fCurrent(other.fCurrent) + { + } + + inline AVLTreeMapIterator(Parent *parent, Node *node = NULL) + : fParent(parent), + fCurrent(node) + { + } + + inline Iterator &operator++() + { + if (fCurrent) + fCurrent = _GetNextNode(fCurrent); + else if (fParent) + fCurrent = _GetLeftMostNode(fParent->fRoot); + return *this; + } + + inline Iterator operator++(int) + { + Iterator it(*this); + ++*this; + return it; + } + + inline Iterator &operator--() + { + if (fCurrent) + fCurrent = _GetPreviousNode(fCurrent); + else if (fParent) + fCurrent = _GetRightMostNode(fParent->fRoot); + return *this; + } + + inline Iterator operator--(int) + { + Iterator it(*this); + --*this; + return it; + } + + inline Iterator &operator=(const Iterator &other) + { + fParent = other.fParent; + fCurrent = other.fCurrent; + return *this; + } + + inline operator bool() const + { + return fCurrent; + } + +private: + static inline Node *_GetPreviousNode(Node *node) + { + if (node) { + // The previous node cannot be in the right subtree. + if (node->left) { + // We have a left subtree, so go to the right-most node. + node = node->left; + while (node->right) + node = node->right; + } else { + // No left subtree: Backtrack our path and stop, where we + // took the right branch. + Node *previous; + do { + previous = node; + node = node->parent; + } while (node && previous == node->left); + } + } + return node; + } + + static inline Node *_GetNextNode(Node *node) + { + if (node) { + // The next node cannot be in the left subtree. + if (node->right) { + // We have a right subtree, so go to the left-most node. + node = node->right; + while (node->left) + node = node->left; + } else { + // No right subtree: Backtrack our path and stop, where we + // took the left branch. + Node *previous; + do { + previous = node; + node = node->parent; + } while (node && previous == node->right); + } + } + return node; + } + + static inline Node *_GetLeftMostNode(Node *node) + { + if (node) { + while (node->left) + node = node->left; + } + return node; + } + + static inline Node *_GetRightMostNode(Node *node) + { + if (node) { + while (node->right) + node = node->right; + } + return node; + } + +protected: + Parent *fParent; + Node *fCurrent; +}; + +// Iterator + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::Iterator::Iterator() + : SuperClass() +{ +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::Iterator::Iterator(const Iterator &other) + : SuperClass(other) +{ +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::Iterator & +_AVL_TREE_MAP_CLASS_NAME::Iterator::operator++() +{ + SuperClass::operator++(); + return *this; +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::Iterator +_AVL_TREE_MAP_CLASS_NAME::Iterator::operator++(int) +{ + Iterator it(*this); + ++*this; + return it; +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::Iterator & +_AVL_TREE_MAP_CLASS_NAME::Iterator::operator--() +{ + SuperClass::operator--(); + return *this; +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::Iterator +_AVL_TREE_MAP_CLASS_NAME::Iterator::operator--(int) +{ + Iterator it(*this); + --*this; + return it; +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::Iterator & +_AVL_TREE_MAP_CLASS_NAME::Iterator::operator=(Iterator &other) +{ + *(SuperClass*)this = other; + return *this; +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::Iterator::Iterator(_AVL_TREE_MAP_CLASS_NAME *parent, + Node *node) + : SuperClass(parent, node) +{ +} + +// ConstIterator + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::ConstIterator::ConstIterator() + : SuperClass() +{ +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::ConstIterator::ConstIterator( + const ConstIterator &other) + : SuperClass(other) +{ +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::ConstIterator::ConstIterator(const Iterator &other) + : SuperClass(other.fParent, other.fCurrent) +{ +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::ConstIterator & +_AVL_TREE_MAP_CLASS_NAME::ConstIterator::operator++() +{ + SuperClass::operator++(); + return *this; +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::ConstIterator +_AVL_TREE_MAP_CLASS_NAME::ConstIterator::operator++(int) +{ + ConstIterator it(*this); + ++*this; + return it; +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::ConstIterator & +_AVL_TREE_MAP_CLASS_NAME::ConstIterator::operator--() +{ + SuperClass::operator--(); + return *this; +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::ConstIterator +_AVL_TREE_MAP_CLASS_NAME::ConstIterator::operator--(int) +{ + Iterator it(*this); + --*this; + return it; +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::ConstIterator & +_AVL_TREE_MAP_CLASS_NAME::ConstIterator::operator=(ConstIterator &other) +{ + *(SuperClass*)this = other; + return *this; +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::ConstIterator & +_AVL_TREE_MAP_CLASS_NAME::ConstIterator::operator=(Iterator &other) +{ + fParent = other.fParent; + fCurrent = other.fCurrent; + return *this; +} + +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::ConstIterator::ConstIterator( + const _AVL_TREE_MAP_CLASS_NAME *parent, Node *node) + : SuperClass(parent, node) +{ +} + + +// AVLTreeMap + +// constructor +_AVL_TREE_MAP_TEMPLATE_LIST +_AVL_TREE_MAP_CLASS_NAME::AVLTreeMap() + : fRoot(NULL), + fNodeCount(0) +{ +} + +// destructor +_AVL_TREE_MAP_TEMPLATE_LIST +_AVL_TREE_MAP_CLASS_NAME::~AVLTreeMap() +{ + _FreeTree(fRoot); + fRoot = NULL; +} + +// MakeEmpty +_AVL_TREE_MAP_TEMPLATE_LIST +void +_AVL_TREE_MAP_CLASS_NAME::MakeEmpty() +{ + _FreeTree(fRoot); + fRoot = NULL; + fNodeCount = 0; +} + +// Find +_AVL_TREE_MAP_TEMPLATE_LIST +_AVL_TREE_MAP_CLASS_NAME::Iterator +_AVL_TREE_MAP_CLASS_NAME::Find(const Key &key) +{ + Node *node = fRoot; + while (node) { + int cmp = Compare(key, GetKey(node)); + if (cmp == 0) + return Iterator(this, node); + if (cmp < 0) + node = node->left; + else + node = node->right; + } + return End(); +} + +// FindClose +_AVL_TREE_MAP_TEMPLATE_LIST +_AVL_TREE_MAP_CLASS_NAME::Iterator +_AVL_TREE_MAP_CLASS_NAME::FindClose(const Key &key, bool less) +{ + Node *node = fRoot; + Node *parent = NULL; + while (node) { + int cmp = Compare(key, GetKey(node)); + if (cmp == 0) + break; + parent = node; + if (cmp < 0) + node = node->left; + else + node = node->right; + } + // not found: try to get close + if (!node && parent) { + node = parent; + int expectedCmp = (less ? -1 : 1); + int cmp = Compare(GetKey(node), key); + if (cmp != expectedCmp) { + // The node's value is less although for a greater value was asked, + // or the other way around. We need to iterate to the next node in + // the right directory. If there is no node, we fail. + if (less) + return ++Iterator(this, node); + return --Iterator(this, node); + } + } + return Iterator(this, node); +} + +// Insert +_AVL_TREE_MAP_TEMPLATE_LIST +status_t +_AVL_TREE_MAP_CLASS_NAME::Insert(const Key &key, const Value &value, + Iterator &iterator) +{ + int result = _Insert(key, value, &fRoot, &iterator); + switch (result) { + case OK: + case HEIGHT_CHANGED: + return B_OK; + case NO_MEMORY: + return B_NO_MEMORY; + case DUPLICATE: + default: + return B_BAD_VALUE; + } +} + +// Remove +_AVL_TREE_MAP_TEMPLATE_LIST +ssize_t +_AVL_TREE_MAP_CLASS_NAME::Remove(const Key &key) +{ + // find node + Node *node = fRoot; + while (node) { + int cmp = Compare(key, GetKey(node)); + if (cmp == 0) + break; + else { + if (cmp < 0) + node = node->left; + else + node = node->right; + } + } + // remove it + int result = _Remove(node); + // set result + switch (result) { + case OK: + case HEIGHT_CHANGED: + return 1; + case NOT_FOUND: + default: + return 0; + } +} + +// Erase +_AVL_TREE_MAP_TEMPLATE_LIST +_AVL_TREE_MAP_CLASS_NAME::Iterator +_AVL_TREE_MAP_CLASS_NAME::Erase(const Iterator &iterator) +{ + Iterator it(iterator); + if (Node *node = it._GetCurrentNode()) { + it.GetNext(); + _Remove(node); + return it; + } + return End(); +} + +// Check +_AVL_TREE_MAP_TEMPLATE_LIST +int +_AVL_TREE_MAP_CLASS_NAME::Check(Node *node, int level, bool levelsOnly) const +{ + int height = 0; + if (node) { + // check root node parent + if (node == fRoot && node->parent != NULL) { + printf("Root node has parent: %p\n", node->parent); + debugger("Root node has parent."); + } + // check children's parents + if (node->left && node->left->parent != node) { + printf("Left child of node has has wrong parent: %p, should be: " + "%p\n", node->left->parent, node); + _DumpNode(node); + debugger("Left child node has wrong parent."); + } + if (node->right && node->right->parent != node) { + printf("Right child of node has has wrong parent: %p, should be: " + "%p\n", node->right->parent, node); + _DumpNode(node); + debugger("Right child node has wrong parent."); + } + // check heights + int leftHeight = Check(node->left, level + 1); + int rightHeight = Check(node->right, level + 1); + if (node->balance_factor != rightHeight - leftHeight) { + printf("Subtree %p at level %d has wrong balance factor: left " + "height: %d, right height: %d, balance factor: %d\n", + node, level, leftHeight, rightHeight, node->balance_factor); + _DumpNode(node); + debugger("Node has wrong balance factor."); + } + // check AVL property + if (!levelsOnly && (leftHeight - rightHeight > 1 + || leftHeight - rightHeight < -1)) { + printf("Subtree %p at level %d violates the AVL property: left " + "height: %d, right height: %d\n", node, level, leftHeight, + rightHeight); + _DumpNode(node); + debugger("Node violates AVL property."); + } + height = (leftHeight > rightHeight ? leftHeight : rightHeight) + 1; + } + return height; +} + +// _RotateRight +_AVL_TREE_MAP_TEMPLATE_LIST +void +_AVL_TREE_MAP_CLASS_NAME::_RotateRight(Node **nodeP) +{ + // rotate the nodes + Node *node = *nodeP; + Node *left = node->left; +//printf("_RotateRight(): balance: node: %d, left: %d\n", +//node->balance_factor, left->balance_factor); + *nodeP = left; + left->parent = node->parent; + node->left = left->right; + if (left->right) + left->right->parent = node; + left->right = node; + node->parent = left; + // adjust the balance factors + // former pivot + if (left->balance_factor >= 0) + node->balance_factor++; + else + node->balance_factor += 1 - left->balance_factor; + // former left + if (node->balance_factor <= 0) + left->balance_factor++; + else + left->balance_factor += node->balance_factor + 1; +//printf("_RotateRight() end: balance: node: %d, left: %d\n", +//node->balance_factor, left->balance_factor); +} + +// _RotateLeft +_AVL_TREE_MAP_TEMPLATE_LIST +void +_AVL_TREE_MAP_CLASS_NAME::_RotateLeft(Node **nodeP) +{ + // rotate the nodes + Node *node = *nodeP; + Node *right = node->right; +//printf("_RotateLeft(): balance: node: %d, right: %d\n", +//node->balance_factor, right->balance_factor); + *nodeP = right; + right->parent = node->parent; + node->right = right->left; + if (right->left) + right->left->parent = node; + right->left = node; + node->parent = right; + // adjust the balance factors + // former pivot + if (right->balance_factor <= 0) + node->balance_factor--; + else + node->balance_factor -= right->balance_factor + 1; + // former right + if (node->balance_factor >= 0) + right->balance_factor--; + else + right->balance_factor += node->balance_factor - 1; +//printf("_RotateLeft() end: balance: node: %d, right: %d\n", +//node->balance_factor, right->balance_factor); +} + +// _BalanceInsertLeft +_AVL_TREE_MAP_TEMPLATE_LIST +int +_AVL_TREE_MAP_CLASS_NAME::_BalanceInsertLeft(Node **node) +{ +//printf("_BalanceInsertLeft()\n"); +//_DumpNode(*node); +//Check(*node, 0, true); + int result = HEIGHT_CHANGED; + if ((*node)->balance_factor < LEFT) { + // tree is left heavy + Node **left = &(*node)->left; + if ((*left)->balance_factor == LEFT) { + // left left heavy + _RotateRight(node); + } else { + // left right heavy + _RotateLeft(left); + _RotateRight(node); + } + result = OK; + } else if ((*node)->balance_factor == BALANCED) + result = OK; +//printf("_BalanceInsertLeft() done: %d\n", result); + return result; +} + +// _BalanceInsertRight +_AVL_TREE_MAP_TEMPLATE_LIST +int +_AVL_TREE_MAP_CLASS_NAME::_BalanceInsertRight(Node **node) +{ +//printf("_BalanceInsertRight()\n"); +//_DumpNode(*node); +//Check(*node, 0, true); + int result = HEIGHT_CHANGED; + if ((*node)->balance_factor > RIGHT) { + // tree is right heavy + Node **right = &(*node)->right; + if ((*right)->balance_factor == RIGHT) { + // right right heavy + _RotateLeft(node); + } else { + // right left heavy + _RotateRight(right); + _RotateLeft(node); + } + result = OK; + } else if ((*node)->balance_factor == BALANCED) + result = OK; +//printf("_BalanceInsertRight() done: %d\n", result); + return result; +} + +// _Insert +_AVL_TREE_MAP_TEMPLATE_LIST +int +_AVL_TREE_MAP_CLASS_NAME::_Insert(const Key &key, const Value &value, + Node **node, Iterator *iterator) +{ + struct node_info { + Node **node; + bool left; + }; + node_info stack[kMaxAVLTreeHeight]; + node_info *top = stack; + const node_info *const bottom = stack; + // find insertion point + while (*node) { + int cmp = Compare(key, GetKey(*node)); + if (cmp == 0) // duplicate node + return DUPLICATE; + else { + top->node = node; + if (cmp < 0) { + top->left = true; + node = &(*node)->left; + } else { + top->left = false; + node = &(*node)->right; + } + top++; + } + } + // allocate and insert node + *node = Allocate(key, value); + if (*node) { + (*node)->balance_factor = BALANCED; + fNodeCount++; + } else + return NO_MEMORY; + if (top != bottom) + (*node)->parent = *top[-1].node; + // init the iterator + if (iterator) + *iterator = Iterator(this, *node); + // do the balancing + int result = HEIGHT_CHANGED; + while (result == HEIGHT_CHANGED && top != bottom) { + top--; + node = top->node; + if (top->left) { + // left + (*node)->balance_factor--; + result = _BalanceInsertLeft(node); + } else { + // right + (*node)->balance_factor++; + result = _BalanceInsertRight(node); + } + } +//Check(*node); + return result; +} + +// _BalanceRemoveLeft +_AVL_TREE_MAP_TEMPLATE_LIST +int +_AVL_TREE_MAP_CLASS_NAME::_BalanceRemoveLeft(Node **node) +{ +//printf("_BalanceRemoveLeft()\n"); +//_DumpNode(*node); +//Check(*node, 0, true); + int result = HEIGHT_CHANGED; + if ((*node)->balance_factor > RIGHT) { + // tree is right heavy + Node **right = &(*node)->right; + if ((*right)->balance_factor == RIGHT) { + // right right heavy + _RotateLeft(node); + } else if ((*right)->balance_factor == BALANCED) { + // right none heavy + _RotateLeft(node); + result = OK; + } else { + // right left heavy + _RotateRight(right); + _RotateLeft(node); + } + } else if ((*node)->balance_factor == RIGHT) + result = OK; +//printf("_BalanceRemoveLeft() done: %d\n", result); + return result; +} + +// _BalanceRemoveRight +_AVL_TREE_MAP_TEMPLATE_LIST +int +_AVL_TREE_MAP_CLASS_NAME::_BalanceRemoveRight(Node **node) +{ +//printf("_BalanceRemoveRight()\n"); +//_DumpNode(*node); +//Check(*node, 0, true); + int result = HEIGHT_CHANGED; + if ((*node)->balance_factor < LEFT) { + // tree is left heavy + Node **left = &(*node)->left; + if ((*left)->balance_factor == LEFT) { + // left left heavy + _RotateRight(node); + } else if ((*left)->balance_factor == BALANCED) { + // left none heavy + _RotateRight(node); + result = OK; + } else { + // left right heavy + _RotateLeft(left); + _RotateRight(node); + } + } else if ((*node)->balance_factor == LEFT) + result = OK; +//printf("_BalanceRemoveRight() done: %d\n", result); + return result; +} + +// _RemoveRightMostChild +_AVL_TREE_MAP_TEMPLATE_LIST +int +_AVL_TREE_MAP_CLASS_NAME::_RemoveRightMostChild(Node **node, Node **foundNode) +{ + Node **stack[kMaxAVLTreeHeight]; + Node ***top = stack; + const Node *const *const *const bottom = stack; + // find the child + while ((*node)->right) { + *top = node; + top++; + node = &(*node)->right; + } + // found the rightmost child: remove it + // the found node might have a left child: replace the node with the + // child + *foundNode = *node; + Node *left = (*node)->left; + if (left) + left->parent = (*node)->parent; + *node = left; + (*foundNode)->left = NULL; + (*foundNode)->parent = NULL; + // balancing + int result = HEIGHT_CHANGED; + while (result == HEIGHT_CHANGED && top != bottom) { + top--; + node = *top; + (*node)->balance_factor--; + result = _BalanceRemoveRight(node); + } + return result; +} + +// _Remove +_AVL_TREE_MAP_TEMPLATE_LIST +int +_AVL_TREE_MAP_CLASS_NAME::_Remove(const Key &key, Node **node) +{ + struct node_info { + Node **node; + bool left; + }; + node_info stack[kMaxAVLTreeHeight]; + node_info *top = stack; + const node_info *const bottom = stack; + // find node + while (*node) { + int cmp = Compare(key, GetKey(*node)); + if (cmp == 0) + break; + else { + top->node = node; + if (cmp < 0) { + top->left = true; + node = &(*node)->left; + } else { + top->left = false; + node = &(*node)->right; + } + top++; + } + } + if (!*node) + return NOT_FOUND; + // remove and free node + int result = HEIGHT_CHANGED; + Node *oldNode = *node; + Node *replace = NULL; + if ((*node)->left && (*node)->right) { + // node has two children + result = _RemoveRightMostChild(&(*node)->left, &replace); + replace->parent = (*node)->parent; + replace->left = (*node)->left; + replace->right = (*node)->right; + if ((*node)->left) // check necessary, if (*node)->left == replace + (*node)->left->parent = replace; + (*node)->right->parent = replace; + replace->balance_factor = (*node)->balance_factor; + *node = replace; + if (result == HEIGHT_CHANGED) { + replace->balance_factor++; + result = _BalanceRemoveLeft(node); + } + } else if ((*node)->left) { + // node has only left child + replace = (*node)->left; + replace->parent = (*node)->parent; + replace->balance_factor = (*node)->balance_factor + 1; + *node = replace; + } else if ((*node)->right) { + // node has only right child + replace = (*node)->right; + replace->parent = (*node)->parent; + replace->balance_factor = (*node)->balance_factor - 1; + *node = replace; + } else { + // node has no child + *node = NULL; + } + Free(oldNode); + fNodeCount--; + // do the balancing + while (result == HEIGHT_CHANGED && top != bottom) { + top--; + node = top->node; + if (top->left) { + // left + (*node)->balance_factor++; + result = _BalanceRemoveLeft(node); + } else { + // right + (*node)->balance_factor--; + result = _BalanceRemoveRight(node); + } + } +//Check(*node); + return result; +} + +// _Remove +_AVL_TREE_MAP_TEMPLATE_LIST +int +_AVL_TREE_MAP_CLASS_NAME::_Remove(Node *node) +{ + if (!node) + return NOT_FOUND; + // remove and free node + Node *parent = node->parent; + bool isLeft = (parent && parent->left == node); + Node **nodeP + = (parent ? (isLeft ? &parent->left : &parent->right) : &fRoot); + int result = HEIGHT_CHANGED; + Node *replace = NULL; + if (node->left && node->right) { + // node has two children + result = _RemoveRightMostChild(&node->left, &replace); + replace->parent = parent; + replace->left = node->left; + replace->right = node->right; + if (node->left) // check necessary, if node->left == replace + node->left->parent = replace; + node->right->parent = replace; + replace->balance_factor = node->balance_factor; + *nodeP = replace; + if (result == HEIGHT_CHANGED) { + replace->balance_factor++; + result = _BalanceRemoveLeft(nodeP); + } + } else if (node->left) { + // node has only left child + replace = node->left; + replace->parent = parent; + replace->balance_factor = node->balance_factor + 1; + *nodeP = replace; + } else if (node->right) { + // node has only right child + replace = node->right; + replace->parent = node->parent; + replace->balance_factor = node->balance_factor - 1; + *nodeP = replace; + } else { + // node has no child + *nodeP = NULL; + } + Free(node); + fNodeCount--; + // do the balancing + while (result == HEIGHT_CHANGED && parent) { + node = parent; + parent = node->parent; + bool oldIsLeft = isLeft; + isLeft = (parent && parent->left == node); + nodeP = (parent ? (isLeft ? &parent->left : &parent->right) : &fRoot); + if (oldIsLeft) { + // left + node->balance_factor++; + result = _BalanceRemoveLeft(nodeP); + } else { + // right + node->balance_factor--; + result = _BalanceRemoveRight(nodeP); + } + } +//Check(node); + return result; +} + +// _FreeTree +_AVL_TREE_MAP_TEMPLATE_LIST +void +_AVL_TREE_MAP_CLASS_NAME::_FreeTree(Node *node) +{ + if (node) { + _FreeTree(node->left); + _FreeTree(node->right); + fAllocator.Free(node); + } +} + +// _DumpNode +_AVL_TREE_MAP_TEMPLATE_LIST +void +_AVL_TREE_MAP_CLASS_NAME::_DumpNode(Node *node) const +{ + if (!node) + return; + + enum node_type { + ROOT, + LEFT, + RIGHT, + }; + struct node_info { + Node *node; + int id; + int parent; + int level; + int type; + }; + + node_info *queue = new(nothrow) node_info[fNodeCount]; + if (!queue) { + printf("_Dump(): Insufficient memory for allocating queue.\n"); + } + node_info *front = queue; + node_info *back = queue; + back->node = node; + back->id = 0; + back->level = 0; + back->type = ROOT; + back++; + int level = 0; + int nextID = 1; + while (front != back) { + // pop front + node_info *current = front; + front++; + // get to the correct level + node = current->node; + if (level < current->level) { + printf("\n"); + level++; + } + // print node + switch (current->type) { + case ROOT: + printf("[%d:%d]", current->id, node->balance_factor); + break; + case LEFT: + printf("[%d:L:%d:%d]", current->id, current->parent, + node->balance_factor); + break; + case RIGHT: + printf("[%d:R:%d:%d]", current->id, current->parent, + node->balance_factor); + break; + } + // add child nodes + if (node->left) { + back->node = node->left; + back->id = nextID++; + back->parent = current->id; + back->level = current->level + 1; + back->type = LEFT; + back++; + } + if (node->right) { + back->node = node->right; + back->id = nextID++; + back->parent = current->id; + back->level = current->level + 1; + back->type = RIGHT; + back++; + } + } + printf("\n\n"); + delete[] queue; +} + +// Allocate +_AVL_TREE_MAP_TEMPLATE_LIST +inline +_AVL_TREE_MAP_CLASS_NAME::Node * +_AVL_TREE_MAP_CLASS_NAME::Allocate(const Key &key, const Value &value) +{ + return fStrategy.Allocate(key, value); +} + +// Free +_AVL_TREE_MAP_TEMPLATE_LIST +inline +void +_AVL_TREE_MAP_CLASS_NAME::Free(Node *node) +{ + return fStrategy.Free(node); +} + +// GetKey +_AVL_TREE_MAP_TEMPLATE_LIST +inline +Key & +_AVL_TREE_MAP_CLASS_NAME::GetKey(Node *node) const +{ + return fStrategy.GetKey(node); +} + +// GetValue +_AVL_TREE_MAP_TEMPLATE_LIST +inline +Value & +_AVL_TREE_MAP_CLASS_NAME::GetValue(Node *node) const +{ + return fStrategy.GetValue(node); +} + +// Compare +_AVL_TREE_MAP_TEMPLATE_LIST +inline +int +_AVL_TREE_MAP_CLASS_NAME::Compare(const Key &a, const Key &b) +{ + return fStrategy.Compare(a, b); +} + + +// strategy parameters + +// Ascending +namespace AVLTreeMapStrategy { +template +class Ascending { + inline int operator()(const Value &a, const Value &b) const + { + if (a < b) + return -1; + else if (a > b) + return 1; + return 0; + } +}; +} + +// Descending +namespace AVLTreeMapStrategy { +template +class Descending { + inline int operator()(const Value &a, const Value &b) const + { + if (a < b) + return -1; + else if (a > b) + return 1; + return 0; + } +}; +} + +// strategies + +// Auto +namespace AVLTreeMapStrategy { +template class Allocator> +class Auto { +public: + class Node + { + public: + Node(const Key &key, const Value &value) + : key(key), + value(value), + parent(NULL), + left(NULL), + right(NULL), + balance_factor(0) + { + } + + Key key; + Value value; + Node *parent; + Node *left; + Node *right; + int balance_factor; + }; + + inline Node *Allocate(const Key &key, const Value &value) + { + Node *result = fAllocator.Allocate(); + if (result) + fAllocator.Construct(result, key, value); + return result; + } + + inline void Free(Node *node) + { + fAllocator.Destruct(node); + fAllocator.Deallocate(node); + } + + inline Key &GetKey(Node *node) const + { + return node->key; + } + + inline Value &GetValue(Node *node) const + { + return node->value; + } + + inline int Compare(const Key &a, const Key &b) + { + return fCompare(a, b); + } + +private: + KeyOrder fCompare; + Allocator fAllocator; +}; +} + +#endif // _AVL_TREE_MAP_H