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