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 #include <osl/diagnose.h> 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 if ( pFind ) 45 { 46 StgAvlNode* p = this; 47 while( p ) 48 { 49 short nRes = p->Compare( pFind ); 50 if( !nRes ) 51 return p; 52 else p = ( nRes < 0 ) ? p->pLeft : p->pRight; 53 } 54 } 55 return NULL; 56 } 57 58 // find point to add node to AVL tree and returns 59 // +/0/- for >/=/< previous 60 61 short StgAvlNode::Locate 62 ( StgAvlNode* pFind, 63 StgAvlNode** pPivot, StgAvlNode **pParent, StgAvlNode** pPrev ) 64 { 65 short nRes = 0; 66 StgAvlNode* pCur = this; 67 68 OSL_ENSURE( pPivot && pParent && pPrev, "The pointers may not be NULL!" ); 69 *pParent = *pPrev = NULL; 70 *pPivot = this; 71 72 // search tree for insertion point 73 if ( pFind ) 74 { 75 while( pCur != NULL ) 76 { 77 // check for pPivot 78 if( pCur->nBalance != 0 ) 79 *pPivot = pCur, *pParent = *pPrev; 80 // save pPrev location and see what direction to go 81 *pPrev = pCur; 82 nRes = pCur->Compare( pFind ); 83 if( nRes == 0 ) 84 break; 85 else pCur = ( nRes < 0 ) ? pCur->pLeft : pCur->pRight; 86 } 87 } 88 89 return( nRes ); 90 } 91 92 // adjust balance factors in AVL tree from pivot down. 93 // Returns delta balance. 94 95 short StgAvlNode::Adjust( StgAvlNode** pHeavy, StgAvlNode* pNew ) 96 { 97 StgAvlNode* pCur = this; 98 short nDelta; 99 // no traversing 100 OSL_ENSURE( pHeavy && pNew, "The pointers is not allowed to be NULL!" ); 101 if( pCur == pNew || !pNew ) 102 return nBalance; 103 104 short nRes = Compare( pNew ); 105 if( nRes > 0 ) 106 { 107 *pHeavy = pCur = pRight; 108 nDelta = -1; 109 } 110 else 111 { 112 *pHeavy = pCur = pLeft; 113 nDelta = 1; 114 } 115 nBalance = 0; 116 while( pCur != pNew ) 117 { 118 nRes = pCur->Compare( pNew ); 119 if( nRes > 0 ) 120 { 121 // height of right increases by 1 122 pCur->nBalance = -1; 123 pCur = pCur->pRight; 124 } 125 else 126 { 127 // height of left increases by 1 128 pCur->nBalance = 1; 129 pCur = pCur->pLeft; 130 } 131 } 132 nBalance = nBalance + nDelta; 133 return nDelta; 134 } 135 136 // perform LL rotation and return new root 137 138 StgAvlNode* StgAvlNode::RotLL() 139 { 140 OSL_ENSURE( pLeft, "The pointer is not allowed to be NULL!" ); 141 StgAvlNode *pHeavy = pLeft; 142 pLeft = pHeavy->pRight; 143 pHeavy->pRight = this; 144 pHeavy->nBalance = nBalance = 0; 145 return pHeavy; 146 } 147 148 // perform LR rotation and return new root 149 150 StgAvlNode* StgAvlNode::RotLR() 151 { 152 OSL_ENSURE( pLeft && pLeft->pRight, "The pointer is not allowed to be NULL!" ); 153 StgAvlNode* pHeavy = pLeft; 154 StgAvlNode* pNewRoot = pHeavy->pRight; 155 156 pHeavy->pRight = pNewRoot->pLeft; 157 pLeft = pNewRoot->pRight; 158 pNewRoot->pLeft = pHeavy; 159 pNewRoot->pRight = this; 160 161 switch( pNewRoot->nBalance ) 162 { 163 case 1: // LR( b ) 164 nBalance = -1; 165 pHeavy->nBalance = 0; 166 break; 167 case -1: // LR( c ) 168 pHeavy->nBalance = 1; 169 nBalance = 0; 170 break; 171 case 0: // LR( a ) 172 nBalance = 0; 173 pHeavy->nBalance = 0; 174 break; 175 } 176 pNewRoot->nBalance = 0; 177 return pNewRoot; 178 } 179 180 // perform RR rotation and return new root 181 182 StgAvlNode* StgAvlNode::RotRR() 183 { 184 OSL_ENSURE( pRight, "The pointer is not allowed to be NULL!" ); 185 StgAvlNode* pHeavy = pRight; 186 pRight = pHeavy->pLeft; 187 pHeavy->pLeft = this; 188 nBalance = pHeavy->nBalance = 0; 189 return pHeavy; 190 } 191 192 // perform the RL rotation and return the new root 193 194 StgAvlNode* StgAvlNode::RotRL() 195 { 196 OSL_ENSURE( pRight && pRight->pLeft, "The pointer is not allowed to be NULL!" ); 197 StgAvlNode* pHeavy = pRight; 198 StgAvlNode* pNewRoot = pHeavy->pLeft; 199 pHeavy->pLeft = pNewRoot->pRight; 200 pRight = pNewRoot->pLeft; 201 pNewRoot->pRight = pHeavy; 202 pNewRoot->pLeft = this; 203 switch( pNewRoot->nBalance ) 204 { 205 case -1: // RL( b ) 206 nBalance = 1; 207 pHeavy->nBalance = 0; 208 break; 209 case 1: // RL( c ) 210 pHeavy->nBalance = -1; 211 nBalance = 0; 212 break; 213 case 0: // RL( a ) 214 nBalance = 0; 215 pHeavy->nBalance = 0; 216 break; 217 } 218 pNewRoot->nBalance = 0; 219 return pNewRoot; 220 } 221 222 // Remove a tree element. Return the removed element or NULL. 223 224 StgAvlNode* StgAvlNode::Rem( StgAvlNode** p, StgAvlNode* pDel, sal_Bool bPtrs ) 225 { 226 if( p && *p && pDel ) 227 { 228 StgAvlNode* pCur = *p; 229 short nRes = bPtrs ? short( pCur == pDel ) : short(pCur->Compare( pDel )); 230 if( !nRes ) 231 { 232 // Element found: remove 233 if( !pCur->pRight ) 234 { 235 *p = pCur->pLeft; pCur->pLeft = NULL; 236 } 237 else if( !pCur->pLeft ) 238 { 239 *p = pCur->pRight; pCur->pRight = NULL; 240 } 241 else 242 { 243 // The damn element has two leaves. Get the 244 // rightmost element of the left subtree (which 245 // is lexically before this element) and replace 246 // this element with the element found. 247 StgAvlNode* last = pCur; 248 StgAvlNode* l; 249 for( l = pCur->pLeft; 250 l->pRight; last = l, l = l->pRight ) {} 251 // remove the element from chain 252 if( l == last->pRight ) 253 last->pRight = l->pLeft; 254 else 255 last->pLeft = l->pLeft; 256 // perform the replacement 257 l->pLeft = pCur->pLeft; 258 l->pRight = pCur->pRight; 259 *p = l; 260 // delete the element 261 pCur->pLeft = pCur->pRight = NULL; 262 } 263 return pCur; 264 } 265 else 266 { 267 if( nRes < 0 ) 268 return Rem( &pCur->pLeft, pDel, bPtrs ); 269 else 270 return Rem( &pCur->pRight, pDel, bPtrs ); 271 } 272 } 273 return NULL; 274 } 275 276 // Enumerate the tree for later iteration 277 278 void StgAvlNode::StgEnum( short& n ) 279 { 280 if( pLeft ) 281 pLeft->StgEnum( n ); 282 nId = n++; 283 if( pRight ) 284 pRight->StgEnum( n ); 285 } 286 287 // Add node to AVL tree. 288 // Return sal_False if the element already exists. 289 290 sal_Bool StgAvlNode::Insert( StgAvlNode** pRoot, StgAvlNode* pIns ) 291 { 292 StgAvlNode* pPivot, *pHeavy, *pNewRoot, *pParent, *pPrev; 293 if ( !pRoot ) 294 return sal_False; 295 296 // special case - empty tree 297 if( *pRoot == NULL ) 298 { 299 *pRoot = pIns; 300 return sal_True; 301 } 302 // find insertion point and return if already present 303 short nRes = (*pRoot)->Locate( pIns, &pPivot, &pParent, &pPrev ); 304 if( !nRes ) 305 return sal_False; 306 OSL_ENSURE( pPivot && pPrev, "The pointers may not be NULL!" ); 307 308 // add new node 309 if( nRes < 0 ) 310 pPrev->pLeft = pIns; 311 else 312 pPrev->pRight = pIns; 313 // rebalance tree 314 short nDelta = pPivot->Adjust( &pHeavy, pIns ); 315 if( pPivot->nBalance >= 2 || pPivot->nBalance <= -2 ) 316 { 317 pHeavy = ( nDelta < 0 ) ? pPivot->pRight : pPivot->pLeft; 318 // left imbalance 319 if( nDelta > 0 ) 320 if( pHeavy->nBalance == 1 ) 321 pNewRoot = pPivot->RotLL(); 322 else 323 pNewRoot = pPivot->RotLR(); 324 // right imbalance 325 else if( pHeavy->nBalance == -1 ) 326 pNewRoot = pPivot->RotRR(); 327 else 328 pNewRoot = pPivot->RotRL(); 329 // relink balanced subtree 330 if( pParent == NULL ) 331 *pRoot = pNewRoot; 332 else if( pPivot == pParent->pLeft ) 333 pParent->pLeft = pNewRoot; 334 else if( pPivot == pParent->pRight ) 335 pParent->pRight = pNewRoot; 336 } 337 return sal_True; 338 } 339 340 // Remove node from tree. Returns sal_True is found and removed. 341 // Actually delete if bDel 342 343 sal_Bool StgAvlNode::Remove( StgAvlNode** pRoot, StgAvlNode* pDel, sal_Bool bDel ) 344 { 345 if ( !pRoot ) 346 return sal_False; 347 348 // special case - empty tree 349 if( *pRoot == NULL ) 350 return sal_False; 351 // delete the element 352 pDel = Rem( pRoot, pDel, sal_False ); 353 if( pDel ) 354 { 355 if( bDel ) 356 delete pDel; 357 // Rebalance the tree the hard way 358 // OS 22.09.95: Auf MD's Wunsch auskommentiert wg. Absturz 359 /* StgAvlNode* pNew = NULL; 360 while( *pRoot ) 361 { 362 StgAvlNode* p = Rem( pRoot, *pRoot, sal_False ); 363 Insert( &pNew, p ); 364 } 365 *pRoot = pNew;*/ 366 return sal_True; 367 } 368 else 369 return sal_False; 370 } 371 372 // Move node to a different tree. Returns sal_True is found and moved. This routine 373 // may be called when the key has changed. 374 375 sal_Bool StgAvlNode::Move 376 ( StgAvlNode** pRoot1, StgAvlNode** pRoot2, StgAvlNode* pMove ) 377 { 378 if ( !pRoot1 ) 379 return sal_False; 380 381 // special case - empty tree 382 if( *pRoot1 == NULL ) 383 return sal_False; 384 pMove = Rem( pRoot1, pMove, sal_False ); 385 if( pMove ) 386 return Insert( pRoot2, pMove ); 387 else 388 return sal_False; 389 } 390 391 ////////////////////////// class AvlIterator ///////////////////////// 392 393 // The iterator walks through a tree one entry by one. 394 395 StgAvlIterator::StgAvlIterator( StgAvlNode* p ) 396 { 397 pRoot = p; 398 nCount = 0; 399 if( p ) 400 p->StgEnum( nCount ); 401 } 402 403 StgAvlNode* StgAvlIterator::Find( short n ) 404 { 405 StgAvlNode* p = pRoot; 406 while( p ) 407 { 408 if( n == p->nId ) 409 break; 410 else p = ( n < p->nId ) ? p->pLeft : p->pRight; 411 } 412 return p; 413 } 414 415 StgAvlNode* StgAvlIterator::First() 416 { 417 nCur = -1; 418 return Next(); 419 } 420 421 StgAvlNode* StgAvlIterator::Last() 422 { 423 nCur = nCount; 424 return Prev(); 425 } 426 427 StgAvlNode* StgAvlIterator::Next() 428 { 429 return Find( ++nCur ); 430 } 431 432 StgAvlNode* StgAvlIterator::Prev() 433 { 434 return Find( --nCur ); 435 } 436 437