xref: /trunk/main/sot/source/sdstor/stgavl.cxx (revision 046d9d1f)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sot.hxx"
26 
27 
28 #include "stgavl.hxx"
29 
30 StgAvlNode::StgAvlNode()
31 {
32     pLeft = pRight = NULL;
33     nBalance = nId = 0;
34 }
35 
36 StgAvlNode::~StgAvlNode()
37 {
38     delete pLeft;
39     delete pRight;
40 }
41 
42 StgAvlNode* StgAvlNode::Find( StgAvlNode* pFind )
43 {
44     StgAvlNode* p = this;
45     while( p )
46     {
47         short nRes = p->Compare( pFind );
48         if( !nRes )
49             return p;
50         else p = ( nRes < 0 ) ? p->pLeft : p->pRight;
51     }
52     return NULL;
53 }
54 
55 // find point to add node to AVL tree and returns
56 // +/0/- for >/=/< previous
57 
58 short StgAvlNode::Locate
59     ( StgAvlNode* pFind,
60       StgAvlNode** pPivot, StgAvlNode **pParent, StgAvlNode** pPrev )
61 {
62     short nRes = 0;
63     StgAvlNode* pCur = this;
64     *pParent = *pPrev = NULL;
65     *pPivot = this;
66 
67     // search tree for insertion point
68 
69     while( pCur != NULL )
70     {
71         // check for pPivot
72         if( pCur->nBalance != 0 )
73             *pPivot = pCur, *pParent = *pPrev;
74         // save pPrev location and see what direction to go
75         *pPrev = pCur;
76         nRes = pCur->Compare( pFind );
77         if( nRes == 0 )
78             break;
79         else pCur = ( nRes < 0 ) ? pCur->pLeft : pCur->pRight;
80     }
81     return( nRes );
82 }
83 
84 // adjust balance factors in AVL tree from pivot down.
85 // Returns delta balance.
86 
87 short StgAvlNode::Adjust( StgAvlNode** pHeavy, StgAvlNode* pNew )
88 {
89     StgAvlNode* pCur = this;
90     short nDelta;
91     // no traversing
92     if( pCur == pNew )
93         return nBalance;
94     short nRes = Compare( pNew );
95     if( nRes > 0 )
96     {
97         *pHeavy = pCur = pRight;
98         nDelta = -1;
99     }
100     else
101     {
102         *pHeavy = pCur = pLeft;
103         nDelta = 1;
104     }
105 	nBalance = 0;
106 	while( pCur != pNew )
107     {
108         nRes = pCur->Compare( pNew );
109         if( nRes > 0 )
110         {
111             // height of right increases by 1
112             pCur->nBalance = -1;
113             pCur = pCur->pRight;
114         }
115         else
116         {
117             // height of left increases by 1
118             pCur->nBalance = 1;
119             pCur = pCur->pLeft;
120         }
121     }
122     nBalance = nBalance + nDelta;
123     return nDelta;
124 }
125 
126 // perform LL rotation and return new root
127 
128 StgAvlNode* StgAvlNode::RotLL()
129 {
130     StgAvlNode *pHeavy = pLeft;
131     pLeft = pHeavy->pRight;
132     pHeavy->pRight = this;
133     pHeavy->nBalance = nBalance = 0;
134     return pHeavy;
135 }
136 
137 // perform LR rotation and return new root
138 
139 StgAvlNode* StgAvlNode::RotLR()
140 {
141 
142     StgAvlNode* pHeavy = pLeft;
143     StgAvlNode* pNewRoot = pHeavy->pRight;
144 
145     pHeavy->pRight = pNewRoot->pLeft;
146     pLeft = pNewRoot->pRight;
147     pNewRoot->pLeft = pHeavy;
148     pNewRoot->pRight = this;
149 
150     switch( pNewRoot->nBalance )
151     {
152         case 1:     // LR( b )
153             nBalance = -1;
154             pHeavy->nBalance = 0;
155             break;
156         case -1:    // LR( c )
157             pHeavy->nBalance = 1;
158             nBalance = 0;
159             break;
160         case 0:     // LR( a )
161             nBalance = 0;
162             pHeavy->nBalance = 0;
163             break;
164     }
165     pNewRoot->nBalance = 0;
166     return pNewRoot;
167 }
168 
169 // perform RR rotation and return new root
170 
171 StgAvlNode* StgAvlNode::RotRR()
172 {
173     StgAvlNode* pHeavy = pRight;
174     pRight = pHeavy->pLeft;
175     pHeavy->pLeft = this;
176     nBalance = pHeavy->nBalance = 0;
177     return pHeavy;
178 }
179 
180 // perform the RL rotation and return the new root
181 
182 StgAvlNode* StgAvlNode::RotRL()
183 {
184     StgAvlNode* pHeavy = pRight;
185     StgAvlNode* pNewRoot = pHeavy->pLeft;
186     pHeavy->pLeft = pNewRoot->pRight;
187     pRight = pNewRoot->pLeft;
188     pNewRoot->pRight = pHeavy;
189     pNewRoot->pLeft = this;
190     switch( pNewRoot->nBalance )
191     {
192         case -1:    // RL( b )
193             nBalance = 1;
194             pHeavy->nBalance = 0;
195             break;
196         case 1:     // RL( c )
197             pHeavy->nBalance = -1;
198             nBalance = 0;
199             break;
200         case 0:     // RL( a )
201             nBalance = 0;
202             pHeavy->nBalance = 0;
203             break;
204     }
205     pNewRoot->nBalance = 0;
206     return pNewRoot;
207 }
208 
209 // Remove a tree element. Return the removed element or NULL.
210 
211 StgAvlNode* StgAvlNode::Rem( StgAvlNode** p, StgAvlNode* pDel, sal_Bool bPtrs )
212 {
213     if( *p )
214     {
215         StgAvlNode* pCur = *p;
216         short nRes = bPtrs ? short( pCur == pDel ) : short(pCur->Compare( pDel ));
217         if( !nRes )
218         {
219             // Element found: remove
220             if( !pCur->pRight )
221             {
222                 *p = pCur->pLeft; pCur->pLeft = NULL;
223             }
224             else if( !pCur->pLeft )
225             {
226                 *p = pCur->pRight; pCur->pRight = NULL;
227             }
228             else
229             {
230                 // The damn element has two leaves. Get the
231                 // rightmost element of the left subtree (which
232                 // is lexically before this element) and replace
233                 // this element with the element found.
234                 StgAvlNode* last = pCur;
235                 StgAvlNode* l;
236                 for( l = pCur->pLeft;
237                      l->pRight; last = l, l = l->pRight ) {}
238                 // remove the element from chain
239                 if( l == last->pRight )
240                     last->pRight = l->pLeft;
241                 else
242                     last->pLeft = l->pLeft;
243                 // perform the replacement
244                 l->pLeft = pCur->pLeft;
245                 l->pRight = pCur->pRight;
246                 *p = l;
247                 // delete the element
248                 pCur->pLeft = pCur->pRight = NULL;
249             }
250             return pCur;
251         }
252         else
253         {
254             if( nRes < 0 )
255                 return Rem( &pCur->pLeft, pDel, bPtrs );
256             else
257                 return Rem( &pCur->pRight, pDel, bPtrs );
258         }
259     }
260     return NULL;
261 }
262 
263 // Enumerate the tree for later iteration
264 
265 void StgAvlNode::StgEnum( short& n )
266 {
267     if( this )
268     {
269         if( pLeft )
270             pLeft->StgEnum( n );
271         nId = n++;
272         if( pRight )
273             pRight->StgEnum( n );
274     }
275 }
276 
277 // Add node to AVL tree.
278 // Return sal_False if the element already exists.
279 
280 sal_Bool StgAvlNode::Insert( StgAvlNode** pRoot, StgAvlNode* pIns )
281 {
282     StgAvlNode* pPivot, *pHeavy, *pNewRoot, *pParent, *pPrev;
283     // special case - empty tree
284     if( *pRoot == NULL )
285     {
286         *pRoot = pIns;
287         return sal_True;
288     }
289     // find insertion point and return if already present
290     short nRes = (*pRoot)->Locate( pIns, &pPivot, &pParent, &pPrev );
291     if( !nRes )
292         return sal_False;
293     // add new node
294     if( nRes < 0 )
295         pPrev->pLeft = pIns;
296     else
297         pPrev->pRight = pIns;
298     // rebalance tree
299     short nDelta = pPivot->Adjust( &pHeavy, pIns );
300     if( pPivot->nBalance >= 2 || pPivot->nBalance <= -2 )
301     {
302         pHeavy = ( nDelta < 0 ) ? pPivot->pRight : pPivot->pLeft;
303         // left imbalance
304         if( nDelta > 0 )
305             if( pHeavy->nBalance == 1 )
306                 pNewRoot = pPivot->RotLL();
307             else
308                 pNewRoot = pPivot->RotLR();
309         // right imbalance
310         else if( pHeavy->nBalance == -1 )
311             pNewRoot = pPivot->RotRR();
312         else
313             pNewRoot = pPivot->RotRL();
314         // relink balanced subtree
315         if( pParent == NULL )
316             *pRoot = pNewRoot;
317         else if( pPivot == pParent->pLeft )
318             pParent->pLeft = pNewRoot;
319         else if( pPivot == pParent->pRight )
320             pParent->pRight = pNewRoot;
321     }
322     return sal_True;
323 }
324 
325 // Remove node from tree. Returns sal_True is found and removed.
326 // Actually delete if bDel
327 
328 sal_Bool StgAvlNode::Remove( StgAvlNode** pRoot, StgAvlNode* pDel, sal_Bool bDel )
329 {
330     // special case - empty tree
331     if( *pRoot == NULL )
332         return sal_False;
333     // delete the element
334     pDel = Rem( pRoot, pDel, sal_False );
335 	if( pDel )
336 	{
337 		if( bDel )
338 			delete pDel;
339 		// Rebalance the tree the hard way
340 		// OS 22.09.95: Auf MD's Wunsch auskommentiert wg. Absturz
341 /*		StgAvlNode* pNew = NULL;
342 		while( *pRoot )
343 		{
344 			StgAvlNode* p = Rem( pRoot, *pRoot, sal_False );
345 			Insert( &pNew, p );
346 		}
347 		*pRoot = pNew;*/
348 		return sal_True;
349 	}
350 	else
351 		return sal_False;
352 }
353 
354 // Move node to a different tree. Returns sal_True is found and moved. This routine
355 // may be called when the key has changed.
356 
357 sal_Bool StgAvlNode::Move
358 	( StgAvlNode** pRoot1, StgAvlNode** pRoot2, StgAvlNode* pMove )
359 {
360     // special case - empty tree
361     if( *pRoot1 == NULL )
362         return sal_False;
363 	pMove = Rem( pRoot1, pMove, sal_False );
364 	if( pMove )
365 		return Insert( pRoot2, pMove );
366 	else
367 		return sal_False;
368 }
369 
370 ////////////////////////// class AvlIterator /////////////////////////
371 
372 // The iterator walks through a tree one entry by one.
373 
374 StgAvlIterator::StgAvlIterator( StgAvlNode* p )
375 {
376     pRoot = p;
377     nCount = 0;
378 	if( p )
379 	    p->StgEnum( nCount );
380 }
381 
382 StgAvlNode* StgAvlIterator::Find( short n )
383 {
384     StgAvlNode* p = pRoot;
385     while( p )
386     {
387         if( n == p->nId )
388             break;
389         else p = ( n < p->nId ) ? p->pLeft : p->pRight;
390     }
391     return p;
392 }
393 
394 StgAvlNode* StgAvlIterator::First()
395 {
396     nCur = -1;
397     return Next();
398 }
399 
400 StgAvlNode* StgAvlIterator::Last()
401 {
402     nCur = nCount;
403     return Prev();
404 }
405 
406 StgAvlNode* StgAvlIterator::Next()
407 {
408     return Find( ++nCur );
409 }
410 
411 StgAvlNode* StgAvlIterator::Prev()
412 {
413     return Find( --nCur );
414 }
415 
416