/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sot.hxx" #include #include "stgavl.hxx" StgAvlNode::StgAvlNode() { pLeft = pRight = NULL; nBalance = nId = 0; } StgAvlNode::~StgAvlNode() { delete pLeft; delete pRight; } StgAvlNode* StgAvlNode::Find( StgAvlNode* pFind ) { if ( 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 = 0; StgAvlNode* pCur = this; OSL_ENSURE( pPivot && pParent && pPrev, "The pointers may not be NULL!" ); *pParent = *pPrev = NULL; *pPivot = this; // search tree for insertion point if ( pFind ) { 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 OSL_ENSURE( pHeavy && pNew, "The pointers is not allowed to be NULL!" ); if( pCur == pNew || !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 = nBalance + nDelta; return nDelta; } // perform LL rotation and return new root StgAvlNode* StgAvlNode::RotLL() { OSL_ENSURE( pLeft, "The pointer is not allowed to be NULL!" ); 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() { OSL_ENSURE( pLeft && pLeft->pRight, "The pointer is not allowed to be NULL!" ); 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() { OSL_ENSURE( pRight, "The pointer is not allowed to be NULL!" ); 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() { OSL_ENSURE( pRight && pRight->pLeft, "The pointer is not allowed to be NULL!" ); 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, sal_Bool bPtrs ) { if( p && *p && pDel ) { StgAvlNode* pCur = *p; short nRes = bPtrs ? short( pCur == pDel ) : short(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::StgEnum( short& n ) { if( pLeft ) pLeft->StgEnum( n ); nId = n++; if( pRight ) pRight->StgEnum( n ); } // Add node to AVL tree. // Return sal_False if the element already exists. sal_Bool StgAvlNode::Insert( StgAvlNode** pRoot, StgAvlNode* pIns ) { StgAvlNode* pPivot, *pHeavy, *pNewRoot, *pParent, *pPrev; if ( !pRoot ) return sal_False; // special case - empty tree if( *pRoot == NULL ) { *pRoot = pIns; return sal_True; } // find insertion point and return if already present short nRes = (*pRoot)->Locate( pIns, &pPivot, &pParent, &pPrev ); if( !nRes ) return sal_False; OSL_ENSURE( pPivot && pPrev, "The pointers may not be NULL!" ); // 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 sal_True; } // Remove node from tree. Returns sal_True is found and removed. // Actually delete if bDel sal_Bool StgAvlNode::Remove( StgAvlNode** pRoot, StgAvlNode* pDel, sal_Bool bDel ) { if ( !pRoot ) return sal_False; // special case - empty tree if( *pRoot == NULL ) return sal_False; // delete the element pDel = Rem( pRoot, pDel, sal_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, sal_False ); Insert( &pNew, p ); } *pRoot = pNew;*/ return sal_True; } else return sal_False; } // Move node to a different tree. Returns sal_True is found and moved. This routine // may be called when the key has changed. sal_Bool StgAvlNode::Move ( StgAvlNode** pRoot1, StgAvlNode** pRoot2, StgAvlNode* pMove ) { if ( !pRoot1 ) return sal_False; // special case - empty tree if( *pRoot1 == NULL ) return sal_False; pMove = Rem( pRoot1, pMove, sal_False ); if( pMove ) return Insert( pRoot2, pMove ); else return sal_False; } ////////////////////////// class AvlIterator ///////////////////////// // The iterator walks through a tree one entry by one. StgAvlIterator::StgAvlIterator( StgAvlNode* p ) { pRoot = p; nCount = 0; if( p ) p->StgEnum( 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 ); }