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