1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <osl/diagnose.h>
23 StgAvlNode::StgAvlNode()
25 pLeft
= pRight
= NULL
;
29 StgAvlNode::~StgAvlNode()
35 StgAvlNode
* StgAvlNode::Find( StgAvlNode
* pFind
)
42 short nRes
= p
->Compare( pFind
);
45 else p
= ( nRes
< 0 ) ? p
->pLeft
: p
->pRight
;
51 // find point to add node to AVL tree and returns
52 // +/0/- for >/=/< previous
54 short StgAvlNode::Locate
56 StgAvlNode
** pPivot
, StgAvlNode
**pParent
, StgAvlNode
** pPrev
)
59 StgAvlNode
* pCur
= this;
61 OSL_ENSURE( pPivot
&& pParent
&& pPrev
, "The pointers may not be NULL!" );
62 *pParent
= *pPrev
= NULL
;
65 // search tree for insertion point
71 if( pCur
->nBalance
!= 0 )
72 *pPivot
= pCur
, *pParent
= *pPrev
;
73 // save pPrev location and see what direction to go
75 nRes
= pCur
->Compare( pFind
);
78 else pCur
= ( nRes
< 0 ) ? pCur
->pLeft
: pCur
->pRight
;
85 // adjust balance factors in AVL tree from pivot down.
86 // Returns delta balance.
88 short StgAvlNode::Adjust( StgAvlNode
** pHeavy
, StgAvlNode
* pNew
)
90 StgAvlNode
* pCur
= this;
93 OSL_ENSURE( pHeavy
&& pNew
, "The pointers is not allowed to be NULL!" );
94 if( pCur
== pNew
|| !pNew
)
97 short nRes
= Compare( pNew
);
100 *pHeavy
= pCur
= pRight
;
105 *pHeavy
= pCur
= pLeft
;
109 while( pCur
!= pNew
)
111 nRes
= pCur
->Compare( pNew
);
114 // height of right increases by 1
120 // height of left increases by 1
125 nBalance
= nBalance
+ nDelta
;
129 // perform LL rotation and return new root
131 StgAvlNode
* StgAvlNode::RotLL()
133 OSL_ENSURE( pLeft
, "The pointer is not allowed to be NULL!" );
134 StgAvlNode
*pHeavy
= pLeft
;
135 pLeft
= pHeavy
->pRight
;
136 pHeavy
->pRight
= this;
137 pHeavy
->nBalance
= nBalance
= 0;
141 // perform LR rotation and return new root
143 StgAvlNode
* StgAvlNode::RotLR()
145 OSL_ENSURE( pLeft
&& pLeft
->pRight
, "The pointer is not allowed to be NULL!" );
146 StgAvlNode
* pHeavy
= pLeft
;
147 StgAvlNode
* pNewRoot
= pHeavy
->pRight
;
149 pHeavy
->pRight
= pNewRoot
->pLeft
;
150 pLeft
= pNewRoot
->pRight
;
151 pNewRoot
->pLeft
= pHeavy
;
152 pNewRoot
->pRight
= this;
154 switch( pNewRoot
->nBalance
)
158 pHeavy
->nBalance
= 0;
161 pHeavy
->nBalance
= 1;
166 pHeavy
->nBalance
= 0;
169 pNewRoot
->nBalance
= 0;
173 // perform RR rotation and return new root
175 StgAvlNode
* StgAvlNode::RotRR()
177 OSL_ENSURE( pRight
, "The pointer is not allowed to be NULL!" );
178 StgAvlNode
* pHeavy
= pRight
;
179 pRight
= pHeavy
->pLeft
;
180 pHeavy
->pLeft
= this;
181 nBalance
= pHeavy
->nBalance
= 0;
185 // perform the RL rotation and return the new root
187 StgAvlNode
* StgAvlNode::RotRL()
189 OSL_ENSURE( pRight
&& pRight
->pLeft
, "The pointer is not allowed to be NULL!" );
190 StgAvlNode
* pHeavy
= pRight
;
191 StgAvlNode
* pNewRoot
= pHeavy
->pLeft
;
192 pHeavy
->pLeft
= pNewRoot
->pRight
;
193 pRight
= pNewRoot
->pLeft
;
194 pNewRoot
->pRight
= pHeavy
;
195 pNewRoot
->pLeft
= this;
196 switch( pNewRoot
->nBalance
)
200 pHeavy
->nBalance
= 0;
203 pHeavy
->nBalance
= -1;
208 pHeavy
->nBalance
= 0;
211 pNewRoot
->nBalance
= 0;
215 // Remove a tree element. Return the removed element or NULL.
217 StgAvlNode
* StgAvlNode::Rem( StgAvlNode
** p
, StgAvlNode
* pDel
, bool bPtrs
)
219 if( p
&& *p
&& pDel
)
221 StgAvlNode
* pCur
= *p
;
222 short nRes
= bPtrs
? short( pCur
== pDel
) : short(pCur
->Compare( pDel
));
225 // Element found: remove
228 *p
= pCur
->pLeft
; pCur
->pLeft
= NULL
;
230 else if( !pCur
->pLeft
)
232 *p
= pCur
->pRight
; pCur
->pRight
= NULL
;
236 // The damn element has two leaves. Get the
237 // rightmost element of the left subtree (which
238 // is lexically before this element) and replace
239 // this element with the element found.
240 StgAvlNode
* last
= pCur
;
242 for( l
= pCur
->pLeft
;
243 l
->pRight
; last
= l
, l
= l
->pRight
) {}
244 // remove the element from chain
245 if( l
== last
->pRight
)
246 last
->pRight
= l
->pLeft
;
248 last
->pLeft
= l
->pLeft
;
249 // perform the replacement
250 l
->pLeft
= pCur
->pLeft
;
251 l
->pRight
= pCur
->pRight
;
253 // delete the element
254 pCur
->pLeft
= pCur
->pRight
= NULL
;
261 return Rem( &pCur
->pLeft
, pDel
, bPtrs
);
263 return Rem( &pCur
->pRight
, pDel
, bPtrs
);
269 // Enumerate the tree for later iteration
271 void StgAvlNode::StgEnum( short& n
)
277 pRight
->StgEnum( n
);
280 // Add node to AVL tree.
281 // Return false if the element already exists.
283 bool StgAvlNode::Insert( StgAvlNode
** pRoot
, StgAvlNode
* pIns
)
285 StgAvlNode
* pPivot
, *pHeavy
, *pNewRoot
, *pParent
, *pPrev
;
289 // special case - empty tree
295 // find insertion point and return if already present
296 short nRes
= (*pRoot
)->Locate( pIns
, &pPivot
, &pParent
, &pPrev
);
299 OSL_ENSURE( pPivot
&& pPrev
, "The pointers may not be NULL!" );
305 pPrev
->pRight
= pIns
;
307 short nDelta
= pPivot
->Adjust( &pHeavy
, pIns
);
308 if( pPivot
->nBalance
>= 2 || pPivot
->nBalance
<= -2 )
310 pHeavy
= ( nDelta
< 0 ) ? pPivot
->pRight
: pPivot
->pLeft
;
313 if( pHeavy
->nBalance
== 1 )
314 pNewRoot
= pPivot
->RotLL();
316 pNewRoot
= pPivot
->RotLR();
318 else if( pHeavy
->nBalance
== -1 )
319 pNewRoot
= pPivot
->RotRR();
321 pNewRoot
= pPivot
->RotRL();
322 // relink balanced subtree
323 if( pParent
== NULL
)
325 else if( pPivot
== pParent
->pLeft
)
326 pParent
->pLeft
= pNewRoot
;
327 else if( pPivot
== pParent
->pRight
)
328 pParent
->pRight
= pNewRoot
;
333 // Remove node from tree. Returns true is found and removed.
334 // Actually delete if bDel
336 bool StgAvlNode::Remove( StgAvlNode
** pRoot
, StgAvlNode
* pDel
, bool bDel
)
341 // special case - empty tree
344 // delete the element
345 pDel
= Rem( pRoot
, pDel
, false );
350 // Rebalance the tree the hard way
351 // OS 22.09.95: Auf MD's Wunsch auskommentiert wg. Absturz
352 /* StgAvlNode* pNew = NULL;
355 StgAvlNode* p = Rem( pRoot, *pRoot, false );
365 // Move node to a different tree. Returns true is found and moved. This routine
366 // may be called when the key has changed.
368 bool StgAvlNode::Move( StgAvlNode
** pRoot1
, StgAvlNode
** pRoot2
, StgAvlNode
* pMove
)
373 // special case - empty tree
374 if( *pRoot1
== NULL
)
376 pMove
= Rem( pRoot1
, pMove
, false );
378 return Insert( pRoot2
, pMove
);
383 ////////////////////////// class AvlIterator /////////////////////////
385 // The iterator walks through a tree one entry by one.
387 StgAvlIterator::StgAvlIterator( StgAvlNode
* p
)
393 p
->StgEnum( nCount
);
396 StgAvlNode
* StgAvlIterator::Find( short n
)
398 StgAvlNode
* p
= pRoot
;
403 else p
= ( n
< p
->nId
) ? p
->pLeft
: p
->pRight
;
408 StgAvlNode
* StgAvlIterator::First()
414 StgAvlNode
* StgAvlIterator::Next()
416 return Find( ++nCur
);
419 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */