/* =========================================================================== Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). Doom 3 Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 Source Code. If not, see . In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ #ifndef __BTREE_H__ #define __BTREE_H__ /* =============================================================================== Balanced Search Tree =============================================================================== */ //#define BTREE_CHECK template< class objType, class keyType > class idBTreeNode { public: keyType key; // key used for sorting objType * object; // if != NULL pointer to object stored in leaf node idBTreeNode * parent; // parent node idBTreeNode * next; // next sibling idBTreeNode * prev; // prev sibling int numChildren; // number of children idBTreeNode * firstChild; // first child idBTreeNode * lastChild; // last child }; template< class objType, class keyType, int maxChildrenPerNode > class idBTree { public: idBTree( void ); ~idBTree( void ); void Init( void ); void Shutdown( void ); idBTreeNode * Add( objType *object, keyType key ); // add an object to the tree void Remove( idBTreeNode *node ); // remove an object node from the tree objType * Find( keyType key ) const; // find an object using the given key objType * FindSmallestLargerEqual( keyType key ) const; // find an object with the smallest key larger equal the given key objType * FindLargestSmallerEqual( keyType key ) const; // find an object with the largest key smaller equal the given key idBTreeNode * GetRoot( void ) const; // returns the root node of the tree int GetNodeCount( void ) const; // returns the total number of nodes in the tree idBTreeNode * GetNext( idBTreeNode *node ) const; // goes through all nodes of the tree idBTreeNode * GetNextLeaf( idBTreeNode *node ) const; // goes through all leaf nodes of the tree private: idBTreeNode * root; idBlockAlloc,128> nodeAllocator; idBTreeNode * AllocNode( void ); void FreeNode( idBTreeNode *node ); void SplitNode( idBTreeNode *node ); idBTreeNode * MergeNodes( idBTreeNode *node1, idBTreeNode *node2 ); void CheckTree_r( idBTreeNode *node, int &numNodes ) const; void CheckTree( void ) const; }; template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTree::idBTree( void ) { assert( maxChildrenPerNode >= 4 ); root = NULL; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTree::~idBTree( void ) { Shutdown(); } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE void idBTree::Init( void ) { root = AllocNode(); } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE void idBTree::Shutdown( void ) { nodeAllocator.Shutdown(); root = NULL; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTreeNode *idBTree::Add( objType *object, keyType key ) { idBTreeNode *node, *child, *newNode; if ( root->numChildren >= maxChildrenPerNode ) { newNode = AllocNode(); newNode->key = root->key; newNode->firstChild = root; newNode->lastChild = root; newNode->numChildren = 1; root->parent = newNode; SplitNode( root ); root = newNode; } newNode = AllocNode(); newNode->key = key; newNode->object = object; for ( node = root; node->firstChild != NULL; node = child ) { if ( key > node->key ) { node->key = key; } // find the first child with a key larger equal to the key of the new node for( child = node->firstChild; child->next; child = child->next ) { if ( key <= child->key ) { break; } } if ( child->object ) { if ( key <= child->key ) { // insert new node before child if ( child->prev ) { child->prev->next = newNode; } else { node->firstChild = newNode; } newNode->prev = child->prev; newNode->next = child; child->prev = newNode; } else { // insert new node after child if ( child->next ) { child->next->prev = newNode; } else { node->lastChild = newNode; } newNode->prev = child; newNode->next = child->next; child->next = newNode; } newNode->parent = node; node->numChildren++; #ifdef BTREE_CHECK CheckTree(); #endif return newNode; } // make sure the child has room to store another node if ( child->numChildren >= maxChildrenPerNode ) { SplitNode( child ); if ( key <= child->prev->key ) { child = child->prev; } } } // we only end up here if the root node is empty newNode->parent = root; root->key = key; root->firstChild = newNode; root->lastChild = newNode; root->numChildren++; #ifdef BTREE_CHECK CheckTree(); #endif return newNode; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE void idBTree::Remove( idBTreeNode *node ) { idBTreeNode *parent; assert( node->object != NULL ); // unlink the node from it's parent if ( node->prev ) { node->prev->next = node->next; } else { node->parent->firstChild = node->next; } if ( node->next ) { node->next->prev = node->prev; } else { node->parent->lastChild = node->prev; } node->parent->numChildren--; // make sure there are no parent nodes with a single child for ( parent = node->parent; parent != root && parent->numChildren <= 1; parent = parent->parent ) { if ( parent->next ) { parent = MergeNodes( parent, parent->next ); } else if ( parent->prev ) { parent = MergeNodes( parent->prev, parent ); } // a parent may not use a key higher than the key of it's last child if ( parent->key > parent->lastChild->key ) { parent->key = parent->lastChild->key; } if ( parent->numChildren > maxChildrenPerNode ) { SplitNode( parent ); break; } } for ( ; parent != NULL && parent->lastChild != NULL; parent = parent->parent ) { // a parent may not use a key higher than the key of it's last child if ( parent->key > parent->lastChild->key ) { parent->key = parent->lastChild->key; } } // free the node FreeNode( node ); // remove the root node if it has a single internal node as child if ( root->numChildren == 1 && root->firstChild->object == NULL ) { idBTreeNode *oldRoot = root; root->firstChild->parent = NULL; root = root->firstChild; FreeNode( oldRoot ); } #ifdef BTREE_CHECK CheckTree(); #endif } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE objType *idBTree::Find( keyType key ) const { idBTreeNode *node; for ( node = root->firstChild; node != NULL; node = node->firstChild ) { while( node->next ) { if ( node->key >= key ) { break; } node = node->next; } if ( node->object ) { if ( node->key == key ) { return node->object; } else { return NULL; } } } return NULL; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE objType *idBTree::FindSmallestLargerEqual( keyType key ) const { idBTreeNode *node; for ( node = root->firstChild; node != NULL; node = node->firstChild ) { while( node->next ) { if ( node->key >= key ) { break; } node = node->next; } if ( node->object ) { if ( node->key >= key ) { return node->object; } else { return NULL; } } } return NULL; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE objType *idBTree::FindLargestSmallerEqual( keyType key ) const { idBTreeNode *node; for ( node = root->lastChild; node != NULL; node = node->lastChild ) { while( node->prev ) { if ( node->key <= key ) { break; } node = node->prev; } if ( node->object ) { if ( node->key <= key ) { return node->object; } else { return NULL; } } } return NULL; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTreeNode *idBTree::GetRoot( void ) const { return root; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE int idBTree::GetNodeCount( void ) const { return nodeAllocator.GetAllocCount(); } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTreeNode *idBTree::GetNext( idBTreeNode *node ) const { if ( node->firstChild ) { return node->firstChild; } else { while( node && node->next == NULL ) { node = node->parent; } return node; } } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTreeNode *idBTree::GetNextLeaf( idBTreeNode *node ) const { if ( node->firstChild ) { while ( node->firstChild ) { node = node->firstChild; } return node; } else { while( node && node->next == NULL ) { node = node->parent; } if ( node ) { node = node->next; while ( node->firstChild ) { node = node->firstChild; } return node; } else { return NULL; } } } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTreeNode *idBTree::AllocNode( void ) { idBTreeNode *node = nodeAllocator.Alloc(); node->key = 0; node->parent = NULL; node->next = NULL; node->prev = NULL; node->numChildren = 0; node->firstChild = NULL; node->lastChild = NULL; node->object = NULL; return node; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE void idBTree::FreeNode( idBTreeNode *node ) { nodeAllocator.Free( node ); } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE void idBTree::SplitNode( idBTreeNode *node ) { int i; idBTreeNode *child, *newNode; // allocate a new node newNode = AllocNode(); newNode->parent = node->parent; // divide the children over the two nodes child = node->firstChild; child->parent = newNode; for ( i = 3; i < node->numChildren; i += 2 ) { child = child->next; child->parent = newNode; } newNode->key = child->key; newNode->numChildren = node->numChildren / 2; newNode->firstChild = node->firstChild; newNode->lastChild = child; node->numChildren -= newNode->numChildren; node->firstChild = child->next; child->next->prev = NULL; child->next = NULL; // add the new child to the parent before the split node assert( node->parent->numChildren < maxChildrenPerNode ); if ( node->prev ) { node->prev->next = newNode; } else { node->parent->firstChild = newNode; } newNode->prev = node->prev; newNode->next = node; node->prev = newNode; node->parent->numChildren++; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTreeNode *idBTree::MergeNodes( idBTreeNode *node1, idBTreeNode *node2 ) { idBTreeNode *child; assert( node1->parent == node2->parent ); assert( node1->next == node2 && node2->prev == node1 ); assert( node1->object == NULL && node2->object == NULL ); assert( node1->numChildren >= 1 && node2->numChildren >= 1 ); for ( child = node1->firstChild; child->next; child = child->next ) { child->parent = node2; } child->parent = node2; child->next = node2->firstChild; node2->firstChild->prev = child; node2->firstChild = node1->firstChild; node2->numChildren += node1->numChildren; // unlink the first node from the parent if ( node1->prev ) { node1->prev->next = node2; } else { node1->parent->firstChild = node2; } node2->prev = node1->prev; node2->parent->numChildren--; FreeNode( node1 ); return node2; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE void idBTree::CheckTree_r( idBTreeNode *node, int &numNodes ) const { int numChildren; idBTreeNode *child; numNodes++; // the root node may have zero children and leaf nodes always have zero children, all other nodes should have at least 2 and at most maxChildrenPerNode children assert( ( node == root ) || ( node->object != NULL && node->numChildren == 0 ) || ( node->numChildren >= 2 && node->numChildren <= maxChildrenPerNode ) ); // the key of a node may never be larger than the key of it's last child assert( ( node->lastChild == NULL ) || ( node->key <= node->lastChild->key ) ); numChildren = 0; for ( child = node->firstChild; child; child = child->next ) { numChildren++; // make sure the children are properly linked if ( child->prev == NULL ) { assert( node->firstChild == child ); } else { assert( child->prev->next == child ); } if ( child->next == NULL ) { assert( node->lastChild == child ); } else { assert( child->next->prev == child ); } // recurse down the tree CheckTree_r( child, numNodes ); } // the number of children should equal the number of linked children assert( numChildren == node->numChildren ); } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE void idBTree::CheckTree( void ) const { int numNodes = 0; idBTreeNode *node, *lastNode; CheckTree_r( root, numNodes ); // the number of nodes in the tree should equal the number of allocated nodes assert( numNodes == nodeAllocator.GetAllocCount() ); // all the leaf nodes should be ordered lastNode = GetNextLeaf( GetRoot() ); if ( lastNode ) { for ( node = GetNextLeaf( lastNode ); node; lastNode = node, node = GetNextLeaf( node ) ) { assert( lastNode->key <= node->key ); } } } #endif /* !__BTREE_H__ */