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 assert(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 if( pCur
== pNew
|| !pNew
)
100 assert(pHeavy
&& pNew
&& "The pointers is not allowed to be NULL!");
102 sal_Int32 nRes
= Compare( pNew
);
105 *pHeavy
= pCur
= m_pRight
;
110 *pHeavy
= pCur
= m_pLeft
;
114 while( pCur
!= pNew
)
116 nRes
= pCur
->Compare( pNew
);
119 // height of right increases by 1
120 pCur
->m_nBalance
= -1;
121 pCur
= pCur
->m_pRight
;
125 // height of left increases by 1
126 pCur
->m_nBalance
= 1;
127 pCur
= pCur
->m_pLeft
;
130 m_nBalance
= m_nBalance
+ nDelta
;
134 // perform LL rotation and return new root
136 StgAvlNode
* StgAvlNode::RotLL()
138 assert(m_pLeft
&& "The pointer is not allowed to be NULL!");
139 StgAvlNode
*pHeavy
= m_pLeft
;
140 m_pLeft
= pHeavy
->m_pRight
;
141 pHeavy
->m_pRight
= this;
142 pHeavy
->m_nBalance
= m_nBalance
= 0;
146 // perform LR rotation and return new root
148 StgAvlNode
* StgAvlNode::RotLR()
150 assert(m_pLeft
&& m_pLeft
->m_pRight
&& "The pointer is not allowed to be NULL!");
151 StgAvlNode
* pHeavy
= m_pLeft
;
152 StgAvlNode
* pNewRoot
= pHeavy
->m_pRight
;
154 pHeavy
->m_pRight
= pNewRoot
->m_pLeft
;
155 m_pLeft
= pNewRoot
->m_pRight
;
156 pNewRoot
->m_pLeft
= pHeavy
;
157 pNewRoot
->m_pRight
= this;
159 switch( pNewRoot
->m_nBalance
)
163 pHeavy
->m_nBalance
= 0;
166 pHeavy
->m_nBalance
= 1;
171 pHeavy
->m_nBalance
= 0;
174 pNewRoot
->m_nBalance
= 0;
178 // perform RR rotation and return new root
179 StgAvlNode
* StgAvlNode::RotRR()
181 assert(m_pRight
&& "The pointer is not allowed to be NULL!" );
182 StgAvlNode
* pHeavy
= m_pRight
;
183 m_pRight
= pHeavy
->m_pLeft
;
184 pHeavy
->m_pLeft
= this;
185 m_nBalance
= pHeavy
->m_nBalance
= 0;
189 // perform the RL rotation and return the new root
190 StgAvlNode
* StgAvlNode::RotRL()
192 assert(m_pRight
&& m_pRight
->m_pLeft
&& "The pointer is not allowed to be NULL!");
193 StgAvlNode
* pHeavy
= m_pRight
;
194 StgAvlNode
* pNewRoot
= pHeavy
->m_pLeft
;
195 pHeavy
->m_pLeft
= pNewRoot
->m_pRight
;
196 m_pRight
= pNewRoot
->m_pLeft
;
197 pNewRoot
->m_pRight
= pHeavy
;
198 pNewRoot
->m_pLeft
= this;
199 switch( pNewRoot
->m_nBalance
)
203 pHeavy
->m_nBalance
= 0;
206 pHeavy
->m_nBalance
= -1;
211 pHeavy
->m_nBalance
= 0;
214 pNewRoot
->m_nBalance
= 0;
218 // Remove a tree element. Return the removed element or NULL.
220 StgAvlNode
* StgAvlNode::Rem( StgAvlNode
** p
, StgAvlNode
* pDel
, bool bPtrs
)
222 if( p
&& *p
&& pDel
)
224 StgAvlNode
* pCur
= *p
;
225 sal_Int32 nRes
= bPtrs
? sal_Int32( pCur
== pDel
) : pCur
->Compare( pDel
);
228 // Element found: remove
229 if( !pCur
->m_pRight
)
231 *p
= pCur
->m_pLeft
; pCur
->m_pLeft
= nullptr;
233 else if( !pCur
->m_pLeft
)
235 *p
= pCur
->m_pRight
; pCur
->m_pRight
= nullptr;
239 // The damn element has two leaves. Get the
240 // rightmost element of the left subtree (which
241 // is lexically before this element) and replace
242 // this element with the element found.
243 StgAvlNode
* last
= pCur
;
245 for( l
= pCur
->m_pLeft
;
246 l
->m_pRight
; last
= l
, l
= l
->m_pRight
) {}
247 // remove the element from chain
248 if( l
== last
->m_pRight
)
249 last
->m_pRight
= l
->m_pLeft
;
251 last
->m_pLeft
= l
->m_pLeft
;
252 // perform the replacement
253 l
->m_pLeft
= pCur
->m_pLeft
;
254 l
->m_pRight
= pCur
->m_pRight
;
256 // delete the element
257 pCur
->m_pLeft
= pCur
->m_pRight
= nullptr;
264 return Rem( &pCur
->m_pLeft
, pDel
, bPtrs
);
266 return Rem( &pCur
->m_pRight
, pDel
, bPtrs
);
272 // Enumerate the tree for later iteration
274 void StgAvlNode::StgEnum( short& n
)
277 m_pLeft
->StgEnum( n
);
280 m_pRight
->StgEnum( n
);
283 // Add node to AVL tree.
284 // Return false if the element already exists.
286 bool StgAvlNode::Insert( StgAvlNode
** pRoot
, StgAvlNode
* pIns
)
288 StgAvlNode
* pPivot
, *pHeavy
, *pParent
, *pPrev
;
292 // special case - empty tree
293 if( *pRoot
== nullptr )
298 // find insertion point and return if already present
299 sal_Int32 nRes
= (*pRoot
)->Locate( pIns
, &pPivot
, &pParent
, &pPrev
);
303 assert(pPivot
&& pPrev
&& "The pointers may not be NULL!");
307 pPrev
->m_pLeft
= pIns
;
309 pPrev
->m_pRight
= pIns
;
311 short nDelta
= pPivot
->Adjust( &pHeavy
, pIns
);
312 if( pPivot
->m_nBalance
>= 2 || pPivot
->m_nBalance
<= -2 )
314 StgAvlNode
* pNewRoot
;
315 pHeavy
= ( nDelta
< 0 ) ? pPivot
->m_pRight
: pPivot
->m_pLeft
;
318 if( pHeavy
->m_nBalance
== 1 )
319 pNewRoot
= pPivot
->RotLL();
321 pNewRoot
= pPivot
->RotLR();
323 else if( pHeavy
->m_nBalance
== -1 )
324 pNewRoot
= pPivot
->RotRR();
326 pNewRoot
= pPivot
->RotRL();
327 // relink balanced subtree
328 if( pParent
== nullptr )
330 else if( pPivot
== pParent
->m_pLeft
)
331 pParent
->m_pLeft
= pNewRoot
;
332 else if( pPivot
== pParent
->m_pRight
)
333 pParent
->m_pRight
= pNewRoot
;
338 // Remove node from tree. Returns true is found and removed.
339 // Actually delete if bDel
341 bool StgAvlNode::Remove( StgAvlNode
** pRoot
, StgAvlNode
* pDel
, bool bDel
)
346 // special case - empty tree
347 if( *pRoot
== nullptr )
349 // delete the element
350 pDel
= Rem( pRoot
, pDel
, false );
355 // Rebalance the tree the hard way
356 // OS 22.09.95: On MD's request commented out due to crash
357 /* StgAvlNode* pNew = NULL;
360 StgAvlNode* p = Rem( pRoot, *pRoot, false );
370 // Move node to a different tree. Returns true is found and moved. This routine
371 // may be called when the key has changed.
374 ////////////////////////// class AvlIterator
376 // The iterator walks through a tree one entry by one.
378 StgAvlIterator::StgAvlIterator( StgAvlNode
* p
)
384 short nCount
= 0; // tree size
385 p
->StgEnum( nCount
);
389 StgAvlNode
* StgAvlIterator::Find( short n
)
391 StgAvlNode
* p
= m_pRoot
;
396 else p
= ( n
< p
->m_nId
) ? p
->m_pLeft
: p
->m_pRight
;
401 StgAvlNode
* StgAvlIterator::First()
407 StgAvlNode
* StgAvlIterator::Next()
409 return Find( ++m_nCur
);
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */