blob: 3835b2955e9629229edfba6ec5c706dc39d405f9 [file] [log] [blame]
/**************************************************************
*
* 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 <osl/diagnose.h>
#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 );
}