1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: stgavl.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sot.hxx"
37 StgAvlNode::StgAvlNode()
39 pLeft
= pRight
= NULL
;
43 StgAvlNode::~StgAvlNode()
49 StgAvlNode
* StgAvlNode::Find( StgAvlNode
* pFind
)
54 short nRes
= p
->Compare( pFind
);
57 else p
= ( nRes
< 0 ) ? p
->pLeft
: p
->pRight
;
62 // find point to add node to AVL tree and returns
63 // +/0/- for >/=/< previous
65 short StgAvlNode::Locate
67 StgAvlNode
** pPivot
, StgAvlNode
**pParent
, StgAvlNode
** pPrev
)
70 StgAvlNode
* pCur
= this;
71 *pParent
= *pPrev
= NULL
;
74 // search tree for insertion point
79 if( pCur
->nBalance
!= 0 )
80 *pPivot
= pCur
, *pParent
= *pPrev
;
81 // save pPrev location and see what direction to go
83 nRes
= pCur
->Compare( pFind
);
86 else pCur
= ( nRes
< 0 ) ? pCur
->pLeft
: pCur
->pRight
;
91 // adjust balance factors in AVL tree from pivot down.
92 // Returns delta balance.
94 short StgAvlNode::Adjust( StgAvlNode
** pHeavy
, StgAvlNode
* pNew
)
96 StgAvlNode
* pCur
= this;
101 short nRes
= Compare( pNew
);
104 *pHeavy
= pCur
= pRight
;
109 *pHeavy
= pCur
= pLeft
;
113 while( pCur
!= pNew
)
115 nRes
= pCur
->Compare( pNew
);
118 // height of right increases by 1
124 // height of left increases by 1
129 nBalance
= nBalance
+ nDelta
;
133 // perform LL rotation and return new root
135 StgAvlNode
* StgAvlNode::RotLL()
137 StgAvlNode
*pHeavy
= pLeft
;
138 pLeft
= pHeavy
->pRight
;
139 pHeavy
->pRight
= this;
140 pHeavy
->nBalance
= nBalance
= 0;
144 // perform LR rotation and return new root
146 StgAvlNode
* StgAvlNode::RotLR()
149 StgAvlNode
* pHeavy
= pLeft
;
150 StgAvlNode
* pNewRoot
= pHeavy
->pRight
;
152 pHeavy
->pRight
= pNewRoot
->pLeft
;
153 pLeft
= pNewRoot
->pRight
;
154 pNewRoot
->pLeft
= pHeavy
;
155 pNewRoot
->pRight
= this;
157 switch( pNewRoot
->nBalance
)
161 pHeavy
->nBalance
= 0;
164 pHeavy
->nBalance
= 1;
169 pHeavy
->nBalance
= 0;
172 pNewRoot
->nBalance
= 0;
176 // perform RR rotation and return new root
178 StgAvlNode
* StgAvlNode::RotRR()
180 StgAvlNode
* pHeavy
= pRight
;
181 pRight
= pHeavy
->pLeft
;
182 pHeavy
->pLeft
= this;
183 nBalance
= pHeavy
->nBalance
= 0;
187 // perform the RL rotation and return the new root
189 StgAvlNode
* StgAvlNode::RotRL()
191 StgAvlNode
* pHeavy
= pRight
;
192 StgAvlNode
* pNewRoot
= pHeavy
->pLeft
;
193 pHeavy
->pLeft
= pNewRoot
->pRight
;
194 pRight
= pNewRoot
->pLeft
;
195 pNewRoot
->pRight
= pHeavy
;
196 pNewRoot
->pLeft
= this;
197 switch( pNewRoot
->nBalance
)
201 pHeavy
->nBalance
= 0;
204 pHeavy
->nBalance
= -1;
209 pHeavy
->nBalance
= 0;
212 pNewRoot
->nBalance
= 0;
216 // Remove a tree element. Return the removed element or NULL.
218 StgAvlNode
* StgAvlNode::Rem( StgAvlNode
** p
, StgAvlNode
* pDel
, BOOL bPtrs
)
222 StgAvlNode
* pCur
= *p
;
223 short nRes
= bPtrs
? short( pCur
== pDel
) : short(pCur
->Compare( pDel
));
226 // Element found: remove
229 *p
= pCur
->pLeft
; pCur
->pLeft
= NULL
;
231 else if( !pCur
->pLeft
)
233 *p
= pCur
->pRight
; pCur
->pRight
= NULL
;
237 // The damn element has two leaves. Get the
238 // rightmost element of the left subtree (which
239 // is lexically before this element) and replace
240 // this element with the element found.
241 StgAvlNode
* last
= pCur
;
243 for( l
= pCur
->pLeft
;
244 l
->pRight
; last
= l
, l
= l
->pRight
) {}
245 // remove the element from chain
246 if( l
== last
->pRight
)
247 last
->pRight
= l
->pLeft
;
249 last
->pLeft
= l
->pLeft
;
250 // perform the replacement
251 l
->pLeft
= pCur
->pLeft
;
252 l
->pRight
= pCur
->pRight
;
254 // delete the element
255 pCur
->pLeft
= pCur
->pRight
= NULL
;
262 return Rem( &pCur
->pLeft
, pDel
, bPtrs
);
264 return Rem( &pCur
->pRight
, pDel
, bPtrs
);
270 // Enumerate the tree for later iteration
272 void StgAvlNode::StgEnum( short& n
)
280 pRight
->StgEnum( n
);
284 // Add node to AVL tree.
285 // Return FALSE if the element already exists.
287 BOOL
StgAvlNode::Insert( StgAvlNode
** pRoot
, StgAvlNode
* pIns
)
289 StgAvlNode
* pPivot
, *pHeavy
, *pNewRoot
, *pParent
, *pPrev
;
290 // special case - empty tree
296 // find insertion point and return if already present
297 short nRes
= (*pRoot
)->Locate( pIns
, &pPivot
, &pParent
, &pPrev
);
304 pPrev
->pRight
= pIns
;
306 short nDelta
= pPivot
->Adjust( &pHeavy
, pIns
);
307 if( pPivot
->nBalance
>= 2 || pPivot
->nBalance
<= -2 )
309 pHeavy
= ( nDelta
< 0 ) ? pPivot
->pRight
: pPivot
->pLeft
;
312 if( pHeavy
->nBalance
== 1 )
313 pNewRoot
= pPivot
->RotLL();
315 pNewRoot
= pPivot
->RotLR();
317 else if( pHeavy
->nBalance
== -1 )
318 pNewRoot
= pPivot
->RotRR();
320 pNewRoot
= pPivot
->RotRL();
321 // relink balanced subtree
322 if( pParent
== NULL
)
324 else if( pPivot
== pParent
->pLeft
)
325 pParent
->pLeft
= pNewRoot
;
326 else if( pPivot
== pParent
->pRight
)
327 pParent
->pRight
= pNewRoot
;
332 // Remove node from tree. Returns TRUE is found and removed.
333 // Actually delete if bDel
335 BOOL
StgAvlNode::Remove( StgAvlNode
** pRoot
, StgAvlNode
* pDel
, BOOL bDel
)
337 // special case - empty tree
340 // delete the element
341 pDel
= Rem( pRoot
, pDel
, FALSE
);
346 // Rebalance the tree the hard way
347 // OS 22.09.95: Auf MD's Wunsch auskommentiert wg. Absturz
348 /* StgAvlNode* pNew = NULL;
351 StgAvlNode* p = Rem( pRoot, *pRoot, FALSE );
361 // Move node to a different tree. Returns TRUE is found and moved. This routine
362 // may be called when the key has changed.
364 BOOL
StgAvlNode::Move
365 ( StgAvlNode
** pRoot1
, StgAvlNode
** pRoot2
, StgAvlNode
* pMove
)
367 // special case - empty tree
368 if( *pRoot1
== NULL
)
370 pMove
= Rem( pRoot1
, pMove
, FALSE
);
372 return Insert( pRoot2
, pMove
);
377 ////////////////////////// class AvlIterator /////////////////////////
379 // The iterator walks through a tree one entry by one.
381 StgAvlIterator::StgAvlIterator( StgAvlNode
* p
)
386 p
->StgEnum( nCount
);
389 StgAvlNode
* StgAvlIterator::Find( short n
)
391 StgAvlNode
* p
= pRoot
;
396 else p
= ( n
< p
->nId
) ? p
->pLeft
: p
->pRight
;
401 StgAvlNode
* StgAvlIterator::First()
407 StgAvlNode
* StgAvlIterator::Last()
413 StgAvlNode
* StgAvlIterator::Next()
415 return Find( ++nCur
);
418 StgAvlNode
* StgAvlIterator::Prev()
420 return Find( --nCur
);