diff options
Diffstat (limited to 'sot/source/sdstor/stgavl.cxx')
-rw-r--r-- | sot/source/sdstor/stgavl.cxx | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/sot/source/sdstor/stgavl.cxx b/sot/source/sdstor/stgavl.cxx new file mode 100644 index 000000000000..bd78852eb8e2 --- /dev/null +++ b/sot/source/sdstor/stgavl.cxx @@ -0,0 +1,451 @@ +/************************************************************************* + * + * $RCSfile: stgavl.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:56:51 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + + +#include "stgavl.hxx" +#pragma hdrstop + +StgAvlNode::StgAvlNode() +{ + pLeft = pRight = NULL; + nBalance = nId = 0; +} + +StgAvlNode::~StgAvlNode() +{ + delete pLeft; + delete pRight; +} + +StgAvlNode* StgAvlNode::Find( StgAvlNode* pFind ) +{ + StgAvlNode* p = this; + while( p ) + { + short nRes = p->Compare( pFind ); + if( !nRes ) + return p; + else p = ( nRes < 0 ) ? p->pLeft : p->pRight; + } + return NULL; +} + +// find point to add node to AVL tree and returns +// +/0/- for >/=/< previous + +short StgAvlNode::Locate + ( StgAvlNode* pFind, + StgAvlNode** pPivot, StgAvlNode **pParent, StgAvlNode** pPrev ) +{ + short nRes; + StgAvlNode* pCur = this; + *pParent = *pPrev = NULL; + *pPivot = this; + + // search tree for insertion point + + while( pCur != NULL ) + { + // check for pPivot + if( pCur->nBalance != 0 ) + *pPivot = pCur, *pParent = *pPrev; + // save pPrev location and see what direction to go + *pPrev = pCur; + nRes = pCur->Compare( pFind ); + if( nRes == 0 ) + break; + else pCur = ( nRes < 0 ) ? pCur->pLeft : pCur->pRight; + } + return( nRes ); +} + +// adjust balance factors in AVL tree from pivot down. +// Returns delta balance. + +short StgAvlNode::Adjust( StgAvlNode** pHeavy, StgAvlNode* pNew ) +{ + StgAvlNode* pCur = this; + short nDelta; + // no traversing + if( pCur == pNew ) + return nBalance; + short nRes = Compare( pNew ); + if( nRes > 0 ) + { + *pHeavy = pCur = pRight; + nDelta = -1; + } + else + { + *pHeavy = pCur = pLeft; + nDelta = 1; + } + nBalance = 0; + while( pCur != pNew ) + { + nRes = pCur->Compare( pNew ); + if( nRes > 0 ) + { + // height of right increases by 1 + pCur->nBalance = -1; + pCur = pCur->pRight; + } + else + { + // height of left increases by 1 + pCur->nBalance = 1; + pCur = pCur->pLeft; + } + } + nBalance += nDelta; + return nDelta; +} + +// perform LL rotation and return new root + +StgAvlNode* StgAvlNode::RotLL() +{ + StgAvlNode *pHeavy = pLeft; + pLeft = pHeavy->pRight; + pHeavy->pRight = this; + pHeavy->nBalance = nBalance = 0; + return pHeavy; +} + +// perform LR rotation and return new root + +StgAvlNode* StgAvlNode::RotLR() +{ + + StgAvlNode* pHeavy = pLeft; + StgAvlNode* pNewRoot = pHeavy->pRight; + + pHeavy->pRight = pNewRoot->pLeft; + pLeft = pNewRoot->pRight; + pNewRoot->pLeft = pHeavy; + pNewRoot->pRight = this; + + switch( pNewRoot->nBalance ) + { + case 1: // LR( b ) + nBalance = -1; + pHeavy->nBalance = 0; + break; + case -1: // LR( c ) + pHeavy->nBalance = 1; + nBalance = 0; + break; + case 0: // LR( a ) + nBalance = 0; + pHeavy->nBalance = 0; + break; + } + pNewRoot->nBalance = 0; + return pNewRoot; +} + +// perform RR rotation and return new root + +StgAvlNode* StgAvlNode::RotRR() +{ + StgAvlNode* pHeavy = pRight; + pRight = pHeavy->pLeft; + pHeavy->pLeft = this; + nBalance = pHeavy->nBalance = 0; + return pHeavy; +} + +// perform the RL rotation and return the new root + +StgAvlNode* StgAvlNode::RotRL() +{ + StgAvlNode* pHeavy = pRight; + StgAvlNode* pNewRoot = pHeavy->pLeft; + pHeavy->pLeft = pNewRoot->pRight; + pRight = pNewRoot->pLeft; + pNewRoot->pRight = pHeavy; + pNewRoot->pLeft = this; + switch( pNewRoot->nBalance ) + { + case -1: // RL( b ) + nBalance = 1; + pHeavy->nBalance = 0; + break; + case 1: // RL( c ) + pHeavy->nBalance = -1; + nBalance = 0; + break; + case 0: // RL( a ) + nBalance = 0; + pHeavy->nBalance = 0; + break; + } + pNewRoot->nBalance = 0; + return pNewRoot; +} + +// Remove a tree element. Return the removed element or NULL. + +StgAvlNode* StgAvlNode::Rem( StgAvlNode** p, StgAvlNode* pDel, BOOL bPtrs ) +{ + if( *p ) + { + StgAvlNode* pCur = *p; + short nRes = bPtrs ? ( pCur == pDel ) : pCur->Compare( pDel ); + if( !nRes ) + { + // Element found: remove + if( !pCur->pRight ) + { + *p = pCur->pLeft; pCur->pLeft = NULL; + } + else if( !pCur->pLeft ) + { + *p = pCur->pRight; pCur->pRight = NULL; + } + else + { + // The damn element has two leaves. Get the + // rightmost element of the left subtree (which + // is lexically before this element) and replace + // this element with the element found. + StgAvlNode* last = pCur; + StgAvlNode* l; + for( l = pCur->pLeft; + l->pRight; last = l, l = l->pRight ) {} + // remove the element from chain + if( l == last->pRight ) + last->pRight = l->pLeft; + else + last->pLeft = l->pLeft; + // perform the replacement + l->pLeft = pCur->pLeft; + l->pRight = pCur->pRight; + *p = l; + // delete the element + pCur->pLeft = pCur->pRight = NULL; + } + return pCur; + } + else + { + if( nRes < 0 ) + return Rem( &pCur->pLeft, pDel, bPtrs ); + else + return Rem( &pCur->pRight, pDel, bPtrs ); + } + } + return NULL; +} + +// Enumerate the tree for later iteration + +void StgAvlNode::Enum( short& n ) +{ + if( this ) + { + if( pLeft ) + pLeft->Enum( n ); + nId = n++; + if( pRight ) + pRight->Enum( n ); + } +} + +// Add node to AVL tree. +// Return FALSE if the element already exists. + +BOOL StgAvlNode::Insert( StgAvlNode** pRoot, StgAvlNode* pIns ) +{ + StgAvlNode* pPivot, *pHeavy, *pNewRoot, *pParent, *pPrev; + // special case - empty tree + if( *pRoot == NULL ) + { + *pRoot = pIns; + return TRUE; + } + // find insertion point and return if already present + short nRes = (*pRoot)->Locate( pIns, &pPivot, &pParent, &pPrev ); + if( !nRes ) + return FALSE; + // add new node + if( nRes < 0 ) + pPrev->pLeft = pIns; + else + pPrev->pRight = pIns; + // rebalance tree + short nDelta = pPivot->Adjust( &pHeavy, pIns ); + if( pPivot->nBalance >= 2 || pPivot->nBalance <= -2 ) + { + pHeavy = ( nDelta < 0 ) ? pPivot->pRight : pPivot->pLeft; + // left imbalance + if( nDelta > 0 ) + if( pHeavy->nBalance == 1 ) + pNewRoot = pPivot->RotLL(); + else + pNewRoot = pPivot->RotLR(); + // right imbalance + else if( pHeavy->nBalance == -1 ) + pNewRoot = pPivot->RotRR(); + else + pNewRoot = pPivot->RotRL(); + // relink balanced subtree + if( pParent == NULL ) + *pRoot = pNewRoot; + else if( pPivot == pParent->pLeft ) + pParent->pLeft = pNewRoot; + else if( pPivot == pParent->pRight ) + pParent->pRight = pNewRoot; + } + return TRUE; +} + +// Remove node from tree. Returns TRUE is found and removed. +// Actually delete if bDel + +BOOL StgAvlNode::Remove( StgAvlNode** pRoot, StgAvlNode* pDel, BOOL bDel ) +{ + // special case - empty tree + if( *pRoot == NULL ) + return FALSE; + // delete the element + pDel = Rem( pRoot, pDel, FALSE ); + if( pDel ) + { + if( bDel ) + delete pDel; + // Rebalance the tree the hard way + // OS 22.09.95: Auf MD's Wunsch auskommentiert wg. Absturz +/* StgAvlNode* pNew = NULL; + while( *pRoot ) + { + StgAvlNode* p = Rem( pRoot, *pRoot, FALSE ); + Insert( &pNew, p ); + } + *pRoot = pNew;*/ + return TRUE; + } + else + return FALSE; +} + +// Move node to a different tree. Returns TRUE is found and moved. This routine +// may be called when the key has changed. + +BOOL StgAvlNode::Move + ( StgAvlNode** pRoot1, StgAvlNode** pRoot2, StgAvlNode* pMove ) +{ + // special case - empty tree + if( *pRoot1 == NULL ) + return FALSE; + pMove = Rem( pRoot1, pMove, FALSE ); + if( pMove ) + return Insert( pRoot2, pMove ); + else + return FALSE; +} + +////////////////////////// class AvlIterator ///////////////////////// + +// The iterator walks through a tree one entry by one. + +StgAvlIterator::StgAvlIterator( StgAvlNode* p ) +{ + pRoot = p; + nCount = 0; + if( p ) + p->Enum( nCount ); +} + +StgAvlNode* StgAvlIterator::Find( short n ) +{ + StgAvlNode* p = pRoot; + while( p ) + { + if( n == p->nId ) + break; + else p = ( n < p->nId ) ? p->pLeft : p->pRight; + } + return p; +} + +StgAvlNode* StgAvlIterator::First() +{ + nCur = -1; + return Next(); +} + +StgAvlNode* StgAvlIterator::Last() +{ + nCur = nCount; + return Prev(); +} + +StgAvlNode* StgAvlIterator::Next() +{ + return Find( ++nCur ); +} + +StgAvlNode* StgAvlIterator::Prev() +{ + return Find( --nCur ); +} + |