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>
24 StgAvlNode::StgAvlNode()
26 m_pLeft
= m_pRight
= nullptr;
27 m_nBalance
= m_nId
= 0;
30 StgAvlNode::~StgAvlNode()
36 StgAvlNode
* StgAvlNode::Find( StgAvlNode
const * pFind
)
43 sal_Int32 nRes
= p
->Compare( pFind
);
46 else p
= ( nRes
< 0 ) ? p
->m_pLeft
: p
->m_pRight
;
52 // find point to add node to AVL tree and returns
53 // +/0/- for >/=/< previous
55 sal_Int32
StgAvlNode::Locate
56 ( StgAvlNode
const * pFind
,
57 StgAvlNode
** pPivot
, StgAvlNode
**pParent
, StgAvlNode
** pPrev
)
60 StgAvlNode
* pCur
= this;
62 OSL_ENSURE( pPivot
&& pParent
&& pPrev
, "The pointers may not be NULL!" );
63 *pParent
= *pPrev
= nullptr;
66 // search tree for insertion point
69 while( pCur
!= nullptr )
72 if( pCur
->m_nBalance
!= 0 )
77 // save pPrev location and see what direction to go
79 nRes
= pCur
->Compare( pFind
);
82 else pCur
= ( nRes
< 0 ) ? pCur
->m_pLeft
: pCur
->m_pRight
;
89 // adjust balance factors in AVL tree from pivot down.
90 // Returns delta balance.
92 short StgAvlNode::Adjust( StgAvlNode
** pHeavy
, StgAvlNode
const * pNew
)
94 StgAvlNode
* pCur
= this;
97 OSL_ENSURE( pHeavy
&& pNew
, "The pointers is not allowed to be NULL!" );
98 if( pCur
== pNew
|| !pNew
)
101 sal_Int32 nRes
= Compare( pNew
);
104 *pHeavy
= pCur
= m_pRight
;
109 *pHeavy
= pCur
= m_pLeft
;
113 while( pCur
!= pNew
)
115 nRes
= pCur
->Compare( pNew
);
118 // height of right increases by 1
119 pCur
->m_nBalance
= -1;
120 pCur
= pCur
->m_pRight
;
124 // height of left increases by 1
125 pCur
->m_nBalance
= 1;
126 pCur
= pCur
->m_pLeft
;
129 m_nBalance
= m_nBalance
+ nDelta
;
133 // perform LL rotation and return new root
135 StgAvlNode
* StgAvlNode::RotLL()
137 assert(m_pLeft
&& "The pointer is not allowed to be NULL!");
138 StgAvlNode
*pHeavy
= m_pLeft
;
139 m_pLeft
= pHeavy
->m_pRight
;
140 pHeavy
->m_pRight
= this;
141 pHeavy
->m_nBalance
= m_nBalance
= 0;
145 // perform LR rotation and return new root
147 StgAvlNode
* StgAvlNode::RotLR()
149 assert(m_pLeft
&& m_pLeft
->m_pRight
&& "The pointer is not allowed to be NULL!");
150 StgAvlNode
* pHeavy
= m_pLeft
;
151 StgAvlNode
* pNewRoot
= pHeavy
->m_pRight
;
153 pHeavy
->m_pRight
= pNewRoot
->m_pLeft
;
154 m_pLeft
= pNewRoot
->m_pRight
;
155 pNewRoot
->m_pLeft
= pHeavy
;
156 pNewRoot
->m_pRight
= this;
158 switch( pNewRoot
->m_nBalance
)
162 pHeavy
->m_nBalance
= 0;
165 pHeavy
->m_nBalance
= 1;
170 pHeavy
->m_nBalance
= 0;
173 pNewRoot
->m_nBalance
= 0;
177 // perform RR rotation and return new root
178 StgAvlNode
* StgAvlNode::RotRR()
180 assert(m_pRight
&& "The pointer is not allowed to be NULL!" );
181 StgAvlNode
* pHeavy
= m_pRight
;
182 m_pRight
= pHeavy
->m_pLeft
;
183 pHeavy
->m_pLeft
= this;
184 m_nBalance
= pHeavy
->m_nBalance
= 0;
188 // perform the RL rotation and return the new root
189 StgAvlNode
* StgAvlNode::RotRL()
191 assert(m_pRight
&& m_pRight
->m_pLeft
&& "The pointer is not allowed to be NULL!");
192 StgAvlNode
* pHeavy
= m_pRight
;
193 StgAvlNode
* pNewRoot
= pHeavy
->m_pLeft
;
194 pHeavy
->m_pLeft
= pNewRoot
->m_pRight
;
195 m_pRight
= pNewRoot
->m_pLeft
;
196 pNewRoot
->m_pRight
= pHeavy
;
197 pNewRoot
->m_pLeft
= this;
198 switch( pNewRoot
->m_nBalance
)
202 pHeavy
->m_nBalance
= 0;
205 pHeavy
->m_nBalance
= -1;
210 pHeavy
->m_nBalance
= 0;
213 pNewRoot
->m_nBalance
= 0;
217 // Remove a tree element. Return the removed element or NULL.
219 StgAvlNode
* StgAvlNode::Rem( StgAvlNode
** p
, StgAvlNode
* pDel
, bool bPtrs
)
221 if( p
&& *p
&& pDel
)
223 StgAvlNode
* pCur
= *p
;
224 sal_Int32 nRes
= bPtrs
? sal_Int32( pCur
== pDel
) : pCur
->Compare( pDel
);
227 // Element found: remove
228 if( !pCur
->m_pRight
)
230 *p
= pCur
->m_pLeft
; pCur
->m_pLeft
= nullptr;
232 else if( !pCur
->m_pLeft
)
234 *p
= pCur
->m_pRight
; pCur
->m_pRight
= nullptr;
238 // The damn element has two leaves. Get the
239 // rightmost element of the left subtree (which
240 // is lexically before this element) and replace
241 // this element with the element found.
242 StgAvlNode
* last
= pCur
;
244 for( l
= pCur
->m_pLeft
;
245 l
->m_pRight
; last
= l
, l
= l
->m_pRight
) {}
246 // remove the element from chain
247 if( l
== last
->m_pRight
)
248 last
->m_pRight
= l
->m_pLeft
;
250 last
->m_pLeft
= l
->m_pLeft
;
251 // perform the replacement
252 l
->m_pLeft
= pCur
->m_pLeft
;
253 l
->m_pRight
= pCur
->m_pRight
;
255 // delete the element
256 pCur
->m_pLeft
= pCur
->m_pRight
= nullptr;
263 return Rem( &pCur
->m_pLeft
, pDel
, bPtrs
);
265 return Rem( &pCur
->m_pRight
, pDel
, bPtrs
);
271 // Enumerate the tree for later iteration
273 void StgAvlNode::StgEnum( short& n
)
276 m_pLeft
->StgEnum( n
);
279 m_pRight
->StgEnum( n
);
282 // Add node to AVL tree.
283 // Return false if the element already exists.
285 bool StgAvlNode::Insert( StgAvlNode
** pRoot
, StgAvlNode
* pIns
)
287 StgAvlNode
* pPivot
, *pHeavy
, *pParent
, *pPrev
;
291 // special case - empty tree
292 if( *pRoot
== nullptr )
297 // find insertion point and return if already present
298 sal_Int32 nRes
= (*pRoot
)->Locate( pIns
, &pPivot
, &pParent
, &pPrev
);
302 assert(pPivot
&& pPrev
&& "The pointers may not be NULL!");
306 pPrev
->m_pLeft
= pIns
;
308 pPrev
->m_pRight
= pIns
;
310 short nDelta
= pPivot
->Adjust( &pHeavy
, pIns
);
311 if( pPivot
->m_nBalance
>= 2 || pPivot
->m_nBalance
<= -2 )
313 StgAvlNode
* pNewRoot
;
314 pHeavy
= ( nDelta
< 0 ) ? pPivot
->m_pRight
: pPivot
->m_pLeft
;
317 if( pHeavy
->m_nBalance
== 1 )
318 pNewRoot
= pPivot
->RotLL();
320 pNewRoot
= pPivot
->RotLR();
322 else if( pHeavy
->m_nBalance
== -1 )
323 pNewRoot
= pPivot
->RotRR();
325 pNewRoot
= pPivot
->RotRL();
326 // relink balanced subtree
327 if( pParent
== nullptr )
329 else if( pPivot
== pParent
->m_pLeft
)
330 pParent
->m_pLeft
= pNewRoot
;
331 else if( pPivot
== pParent
->m_pRight
)
332 pParent
->m_pRight
= pNewRoot
;
337 // Remove node from tree. Returns true is found and removed.
338 // Actually delete if bDel
340 bool StgAvlNode::Remove( StgAvlNode
** pRoot
, StgAvlNode
* pDel
, bool bDel
)
345 // special case - empty tree
346 if( *pRoot
== nullptr )
348 // delete the element
349 pDel
= Rem( pRoot
, pDel
, false );
354 // Rebalance the tree the hard way
355 // OS 22.09.95: On MD's request commented out due to crash
356 /* StgAvlNode* pNew = NULL;
359 StgAvlNode* p = Rem( pRoot, *pRoot, false );
369 // Move node to a different tree. Returns true is found and moved. This routine
370 // may be called when the key has changed.
373 ////////////////////////// class AvlIterator
375 // The iterator walks through a tree one entry by one.
377 StgAvlIterator::StgAvlIterator( StgAvlNode
* p
)
383 short nCount
= 0; // tree size
384 p
->StgEnum( nCount
);
388 StgAvlNode
* StgAvlIterator::Find( short n
)
390 StgAvlNode
* p
= m_pRoot
;
395 else p
= ( n
< p
->m_nId
) ? p
->m_pLeft
: p
->m_pRight
;
400 StgAvlNode
* StgAvlIterator::First()
406 StgAvlNode
* StgAvlIterator::Next()
408 return Find( ++m_nCur
);
411 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */