Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensplaytree.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS system libraries 00004 * PURPOSE: Splay-Tree implementation 00005 * FILE: lib/rtl/splaytree.c 00006 * PROGRAMMER: Alex Ionescu (alex@relsoft.net) 00007 */ 00008 00009 /* INCLUDES *****************************************************************/ 00010 00011 #include <rtl.h> 00012 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 //#define VERIFY_SWAP_SPLAY_LINKS 00017 00018 /* FUNCTIONS ***************************************************************/ 00019 00020 static 00021 VOID 00022 FixupChildLinks(PRTL_SPLAY_LINKS Links, BOOLEAN Root, BOOLEAN LeftChild) 00023 { 00024 if (RtlLeftChild(Links)) { 00025 RtlInsertAsLeftChild(Links, RtlLeftChild(Links)); 00026 } 00027 if (RtlRightChild(Links)) { 00028 RtlInsertAsRightChild(Links, RtlRightChild(Links)); 00029 } 00030 if (!Root) { 00031 if (LeftChild) { 00032 RtlInsertAsLeftChild(RtlParent(Links), Links); 00033 } else { 00034 RtlInsertAsRightChild(RtlParent(Links), Links); 00035 } 00036 } 00037 } 00038 00039 /* 00040 00041 Given the tree: 00042 D 00043 B F 00044 A C E G 00045 00046 Swap(Q,S): 00047 00048 Q S Q.P Q.L Q.R S.P S.L S.R 00049 A C S.P S.L S.R Q.P Q.L Q.R 00050 B A S S.L S.R Q.P Q Q.R 00051 B C S S.L S.R Q.P Q.L Q 00052 D A S.P S.L S.R S Q.L Q.R 00053 D B S S.L S.R S Q Q.R 00054 D F S S.L S.R S Q.L Q 00055 00056 When Q is the immediate parent of S, 00057 Set Q's parent to S, and the proper child ptr of S to Q 00058 When Q is the root, 00059 Set S's parent to S 00060 */ 00061 00062 static 00063 VOID 00064 SwapSplayLinks(PRTL_SPLAY_LINKS LinkA, 00065 PRTL_SPLAY_LINKS LinkB) 00066 { 00067 if (RtlParent(LinkA) == LinkB || RtlIsRoot(LinkB)) { 00068 PRTL_SPLAY_LINKS Tmp = LinkA; 00069 LinkA = LinkB; 00070 LinkB = Tmp; 00071 } 00072 00073 { 00074 RTL_SPLAY_LINKS Ta = *LinkA, Tb = *LinkB; 00075 BOOLEAN RootA = RtlIsRoot(LinkA), 00076 LeftA = RtlIsLeftChild(LinkA), 00077 LeftB = RtlIsLeftChild(LinkB); 00078 *LinkB = Ta; *LinkA = Tb; 00079 00080 // A was parent of B is a special case: A->Parent is now B 00081 if (RtlParent(&Tb) == LinkA) { 00082 if (!RootA) { 00083 if (LeftA) { 00084 RtlInsertAsLeftChild(RtlParent(&Ta), LinkB); 00085 } else { 00086 RtlInsertAsRightChild(RtlParent(&Ta), LinkB); 00087 } 00088 } 00089 if (LeftB) { 00090 RtlInsertAsLeftChild(LinkB, LinkA); 00091 } else { 00092 RtlInsertAsRightChild(LinkB, LinkA); 00093 } 00094 } 00095 00096 FixupChildLinks(LinkA, FALSE, LeftB); 00097 FixupChildLinks(LinkB, RootA, LeftA); 00098 00099 // A was root is a special case: B->Parent is now B 00100 if (RootA) 00101 RtlParent(LinkB) = LinkB; 00102 00103 #ifdef VERIFY_SWAP_SPLAY_LINKS 00104 // Verify the distinct cases of node swap 00105 if (RootA) { 00106 if (RtlParent(&Tb) == LinkA) { 00107 // LinkA = D, LinkB = B 00108 // D B S S.L S.R S Q Q.R 00109 ASSERT(RtlParent(LinkA) == LinkB); 00110 ASSERT(RtlLeftChild(LinkA) == RtlLeftChild(&Tb)); 00111 ASSERT(RtlRightChild(LinkA) == RtlRightChild(&Tb)); 00112 ASSERT(RtlParent(LinkB) == LinkB); 00113 ASSERT(RtlLeftChild(LinkB) == (LeftB ? LinkA : RtlLeftChild(&Ta))); 00114 ASSERT(RtlRightChild(LinkB) == (LeftB ? RtlRightChild(&Ta) : LinkA)); 00115 } else { 00116 // LinkA = D, LinkB = A 00117 // D A S.P S.L S.R S Q.L Q.R 00118 ASSERT(RtlParent(LinkA) == RtlParent(&Tb)); 00119 ASSERT(RtlLeftChild(LinkA) == RtlLeftChild(&Tb)); 00120 ASSERT(RtlRightChild(LinkA) == RtlRightChild(&Tb)); 00121 ASSERT(RtlParent(LinkB) == LinkB); 00122 ASSERT(RtlLeftChild(LinkB) == RtlLeftChild(&Ta)); 00123 ASSERT(RtlRightChild(LinkB) == RtlRightChild(&Ta)); 00124 } 00125 } else { 00126 if (RtlParent(&Tb) == LinkA) { 00127 // LinkA = B, LinkB = A 00128 // B A S S.L S.R Q.P Q Q.R 00129 ASSERT(RtlParent(LinkA) == LinkB); 00130 ASSERT(RtlLeftChild(LinkA) == RtlLeftChild(&Tb)); 00131 ASSERT(RtlRightChild(LinkA) == RtlRightChild(&Tb)); 00132 ASSERT(RtlParent(LinkB) == RtlParent(&Ta)); 00133 ASSERT(RtlLeftChild(LinkB) == (LeftB ? LinkA : RtlLeftChild(&Ta))); 00134 ASSERT(RtlRightChild(LinkB) == (LeftB ? RtlRightChild(&Ta) : LinkA)); 00135 } else { 00136 // LinkA = A, LinkB = C 00137 // A C S.P S.L S.R Q.P Q.L Q.R 00138 ASSERT(!memcmp(LinkA, &Tb, sizeof(Tb))); 00139 ASSERT(!memcmp(LinkB, &Ta, sizeof(Ta))); 00140 } 00141 } 00142 #endif 00143 } 00144 } 00145 00146 /* 00147 * @implemented 00148 */ 00149 PRTL_SPLAY_LINKS 00150 NTAPI 00151 RtlDelete(PRTL_SPLAY_LINKS Links) 00152 { 00153 PRTL_SPLAY_LINKS N, P, C, SP; 00154 N = Links; 00155 00156 /* Check if we have two children */ 00157 if ((RtlLeftChild(N)) && (RtlRightChild(N))) 00158 { 00159 /* Get the predecessor */ 00160 SP = RtlSubtreePredecessor(N); 00161 00162 /* Swap it with N, this will guarantee that N will have only a child */ 00163 SwapSplayLinks(SP, N); 00164 } 00165 00166 /* Check if we have no children */ 00167 if (!(RtlLeftChild(N)) && !(RtlRightChild(N))) 00168 { 00169 /* If we are also the root, then the tree is gone */ 00170 if (RtlIsRoot(N)) return NULL; 00171 00172 /* Get our parent */ 00173 P = RtlParent(N); 00174 00175 /* Find out who is referencing us and delete the reference */ 00176 if (RtlIsLeftChild(N)) 00177 { 00178 /* N was a left child, so erase its parent's left child link */ 00179 RtlLeftChild(RtlParent(N)) = NULL; 00180 } 00181 else 00182 { 00183 /* N was a right child, so erase its parent's right child link */ 00184 RtlRightChild(RtlParent(N)) = NULL; 00185 } 00186 00187 /* And finally splay the parent */ 00188 return RtlSplay(P); 00189 } 00190 00191 /* If we got here, we have a child (not two: we swapped above!) */ 00192 if (RtlLeftChild(N)) 00193 { 00194 /* We have a left child, so get it */ 00195 C = RtlLeftChild(N); 00196 } 00197 else 00198 { 00199 /* We have a right child, get him instead */ 00200 C = RtlRightChild(N); 00201 } 00202 00203 /* Check if we are the root entry */ 00204 if (RtlIsRoot(N)) 00205 { 00206 /* Our child is now root, return him */ 00207 C->Parent = C; 00208 return C; 00209 } 00210 00211 /* Find out who is referencing us and link to our child instead */ 00212 if (RtlIsLeftChild(N)) 00213 { 00214 /* N was a left child, so set its parent's left child as our child */ 00215 RtlLeftChild(RtlParent(N)) = C; 00216 } 00217 else 00218 { 00219 /* N was a right child, so set its parent's right child as our child */ 00220 RtlRightChild(RtlParent(N)) = C; 00221 } 00222 00223 /* Finally, inherit our parent and splay the parent */ 00224 C->Parent = N->Parent; 00225 return RtlSplay(RtlParent(C)); 00226 } 00227 00228 /* 00229 * @unimplemented 00230 */ 00231 VOID 00232 NTAPI 00233 RtlDeleteNoSplay(PRTL_SPLAY_LINKS Links, 00234 PRTL_SPLAY_LINKS *Root) 00235 { 00236 UNIMPLEMENTED; 00237 } 00238 00239 /* 00240 * @implemented 00241 */ 00242 PRTL_SPLAY_LINKS 00243 NTAPI 00244 RtlRealPredecessor(PRTL_SPLAY_LINKS Links) 00245 { 00246 PRTL_SPLAY_LINKS Child; 00247 00248 /* Get the left child */ 00249 Child = RtlLeftChild(Links); 00250 if (Child) 00251 { 00252 /* Get right-most child */ 00253 while (RtlRightChild(Child)) Child = RtlRightChild(Child); 00254 return Child; 00255 } 00256 00257 /* We don't have a left child, keep looping until we find our parent */ 00258 Child = Links; 00259 while (RtlIsLeftChild(Child)) Child = RtlParent(Child); 00260 00261 /* The parent should be a right child, return the real predecessor */ 00262 if (RtlIsRightChild(Child)) return RtlParent(Child); 00263 00264 /* The parent isn't a right child, so no real precessor for us */ 00265 return NULL; 00266 } 00267 00268 /* 00269 * @implemented 00270 */ 00271 PRTL_SPLAY_LINKS 00272 NTAPI 00273 RtlRealSuccessor(PRTL_SPLAY_LINKS Links) 00274 { 00275 PRTL_SPLAY_LINKS Child; 00276 00277 /* Get the right child */ 00278 Child = RtlRightChild(Links); 00279 if (Child) 00280 { 00281 /* Get left-most child */ 00282 while (RtlLeftChild(Child)) Child = RtlLeftChild(Child); 00283 return Child; 00284 } 00285 00286 /* We don't have a right child, keep looping until we find our parent */ 00287 Child = Links; 00288 while (RtlIsRightChild(Child)) Child = RtlParent(Child); 00289 00290 /* The parent should be a left child, return the real successor */ 00291 if (RtlIsLeftChild(Child)) return RtlParent(Child); 00292 00293 /* The parent isn't a right child, so no real successor for us */ 00294 return NULL; 00295 } 00296 00297 /* 00298 * @implemented 00299 */ 00300 PRTL_SPLAY_LINKS 00301 NTAPI 00302 RtlSplay(PRTL_SPLAY_LINKS Links) 00303 { 00304 /* 00305 * Implementation Notes (http://en.wikipedia.org/wiki/Splay_tree): 00306 * 00307 * To do a splay, we carry out a sequence of rotations, 00308 * each of which moves the target node N closer to the root. 00309 * 00310 * Each particular step depends on only two factors: 00311 * - Whether N is the left or right child of its parent node, P, 00312 * - Whether P is the left or right child of its parent, G (for grandparent node). 00313 * 00314 * Thus, there are four cases: 00315 * - Case 1: N is the left child of P and P is the left child of G. 00316 * In this case we perform a double right rotation, so that 00317 * P becomes N's right child, and G becomes P's right child. 00318 * 00319 * - Case 2: N is the right child of P and P is the right child of G. 00320 * In this case we perform a double left rotation, so that 00321 * P becomes N's left child, and G becomes P's left child. 00322 * 00323 * - Case 3: N is the left child of P and P is the right child of G. 00324 * In this case we perform a rotation so that 00325 * G becomes N's left child, and P becomes N's right child. 00326 * 00327 * - Case 4: N is the right child of P and P is the left child of G. 00328 * In this case we perform a rotation so that 00329 * P becomes N's left child, and G becomes N's right child. 00330 * 00331 * Finally, if N doesn't have a grandparent node, we simply perform a 00332 * left or right rotation to move it to the root. 00333 * 00334 * By performing a splay on the node of interest after every operation, 00335 * we keep recently accessed nodes near the root and keep the tree 00336 * roughly balanced, so that we achieve the desired amortized time bounds. 00337 */ 00338 PRTL_SPLAY_LINKS N, P, G; 00339 00340 /* N is the item we'll be playing with */ 00341 N = Links; 00342 00343 /* Let the algorithm run until N becomes the root entry */ 00344 while (!RtlIsRoot(N)) 00345 { 00346 /* Now get the parent and grand-parent */ 00347 P = RtlParent(N); 00348 G = RtlParent(P); 00349 00350 /* Case 1 & 3: N is left child of P */ 00351 if (RtlIsLeftChild(N)) 00352 { 00353 /* Case 1: P is the left child of G */ 00354 if (RtlIsLeftChild(P)) 00355 { 00356 /* 00357 * N's right-child becomes P's left child and 00358 * P's right-child becomes G's left child. 00359 */ 00360 RtlLeftChild(P) = RtlRightChild(N); 00361 RtlLeftChild(G) = RtlRightChild(P); 00362 00363 /* 00364 * If they exist, update their parent pointers too, 00365 * since they've changed trees. 00366 */ 00367 if (RtlLeftChild(P)) RtlParent(RtlLeftChild(P)) = P; 00368 if (RtlLeftChild(G)) RtlParent(RtlLeftChild(G)) = G; 00369 00370 /* 00371 * Now we'll shove N all the way to the top. 00372 * Check if G is the root first. 00373 */ 00374 if (RtlIsRoot(G)) 00375 { 00376 /* G doesn't have a parent, so N will become the root! */ 00377 RtlParent(N) = N; 00378 } 00379 else 00380 { 00381 /* G has a parent, so inherit it since we take G's place */ 00382 RtlParent(N) = RtlParent(G); 00383 00384 /* 00385 * Now find out who was referencing G and have it reference 00386 * N instead, since we're taking G's place. 00387 */ 00388 if (RtlIsLeftChild(G)) 00389 { 00390 /* 00391 * G was a left child, so change its parent's left 00392 * child link to point to N now. 00393 */ 00394 RtlLeftChild(RtlParent(G)) = N; 00395 } 00396 else 00397 { 00398 /* 00399 * G was a right child, so change its parent's right 00400 * child link to point to N now. 00401 */ 00402 RtlRightChild(RtlParent(G)) = N; 00403 } 00404 } 00405 00406 /* Now N is on top, so P has become its child. */ 00407 RtlRightChild(N) = P; 00408 RtlParent(P) = N; 00409 00410 /* N is on top, P is its child, so G is grandchild. */ 00411 RtlRightChild(P) = G; 00412 RtlParent(G) = P; 00413 } 00414 /* Case 3: P is the right child of G */ 00415 else if (RtlIsRightChild(P)) 00416 { 00417 /* 00418 * N's left-child becomes G's right child and 00419 * N's right-child becomes P's left child. 00420 */ 00421 RtlRightChild(G) = RtlLeftChild(N); 00422 RtlLeftChild(P) = RtlRightChild(N); 00423 00424 /* 00425 * If they exist, update their parent pointers too, 00426 * since they've changed trees. 00427 */ 00428 if (RtlRightChild(G)) RtlParent(RtlRightChild(G)) = G; 00429 if (RtlLeftChild(P)) RtlParent(RtlLeftChild(P)) = P; 00430 00431 /* 00432 * Now we'll shove N all the way to the top. 00433 * Check if G is the root first. 00434 */ 00435 if (RtlIsRoot(G)) 00436 { 00437 /* G doesn't have a parent, so N will become the root! */ 00438 RtlParent(N) = N; 00439 } 00440 else 00441 { 00442 /* G has a parent, so inherit it since we take G's place */ 00443 RtlParent(N) = RtlParent(G); 00444 00445 /* 00446 * Now find out who was referencing G and have it reference 00447 * N instead, since we're taking G's place. 00448 */ 00449 if (RtlIsLeftChild(G)) 00450 { 00451 /* 00452 * G was a left child, so change its parent's left 00453 * child link to point to N now. 00454 */ 00455 RtlLeftChild(RtlParent(G)) = N; 00456 } 00457 else 00458 { 00459 /* 00460 * G was a right child, so change its parent's right 00461 * child link to point to N now. 00462 */ 00463 RtlRightChild(RtlParent(G)) = N; 00464 } 00465 } 00466 00467 /* Now N is on top, so G has become its left child. */ 00468 RtlLeftChild(N) = G; 00469 RtlParent(G) = N; 00470 00471 /* N is on top, G is its left child, so P is right child. */ 00472 RtlRightChild(N) = P; 00473 RtlParent(P) = N; 00474 } 00475 /* "Finally" case: N doesn't have a grandparent => P is root */ 00476 else 00477 { 00478 /* P's left-child becomes N's right child */ 00479 RtlLeftChild(P) = RtlRightChild(N); 00480 00481 /* If it exists, update its parent pointer too */ 00482 if (RtlLeftChild(P)) RtlParent(RtlLeftChild(P)) = P; 00483 00484 /* Now make N the root, no need to worry about references */ 00485 N->Parent = N; 00486 00487 /* And make P its right child */ 00488 N->RightChild = P; 00489 P->Parent = N; 00490 } 00491 } 00492 /* Case 2 & 4: N is right child of P */ 00493 else 00494 { 00495 /* Case 2: P is the right child of G */ 00496 if (RtlIsRightChild(P)) 00497 { 00498 /* 00499 * P's left-child becomes G's right child and 00500 * N's left-child becomes P's right child. 00501 */ 00502 RtlRightChild(G) = RtlLeftChild(P); 00503 RtlRightChild(P) = RtlLeftChild(N); 00504 00505 /* 00506 * If they exist, update their parent pointers too, 00507 * since they've changed trees. 00508 */ 00509 if (RtlRightChild(G)) RtlParent(RtlRightChild(G)) = G; 00510 if (RtlRightChild(P)) RtlParent(RtlRightChild(P)) = P; 00511 00512 /* 00513 * Now we'll shove N all the way to the top. 00514 * Check if G is the root first. 00515 */ 00516 if (RtlIsRoot(G)) 00517 { 00518 /* G doesn't have a parent, so N will become the root! */ 00519 RtlParent(N) = N; 00520 } 00521 else 00522 { 00523 /* G has a parent, so inherit it since we take G's place */ 00524 RtlParent(N) = RtlParent(G); 00525 00526 /* 00527 * Now find out who was referencing G and have it reference 00528 * N instead, since we're taking G's place. 00529 */ 00530 if (RtlIsLeftChild(G)) 00531 { 00532 /* 00533 * G was a left child, so change its parent's left 00534 * child link to point to N now. 00535 */ 00536 RtlLeftChild(RtlParent(G)) = N; 00537 } 00538 else 00539 { 00540 /* 00541 * G was a right child, so change its parent's right 00542 * child link to point to N now. 00543 */ 00544 RtlRightChild(RtlParent(G)) = N; 00545 } 00546 } 00547 00548 /* Now N is on top, so P has become its child. */ 00549 RtlLeftChild(N) = P; 00550 RtlParent(P) = N; 00551 00552 /* N is on top, P is its child, so G is grandchild. */ 00553 RtlLeftChild(P) = G; 00554 RtlParent(G) = P; 00555 } 00556 /* Case 4: P is the left child of G */ 00557 else if (RtlIsLeftChild(P)) 00558 { 00559 /* 00560 * N's left-child becomes G's right child and 00561 * N's right-child becomes P's left child. 00562 */ 00563 RtlRightChild(P) = RtlLeftChild(N); 00564 RtlLeftChild(G) = RtlRightChild(N); 00565 00566 /* 00567 * If they exist, update their parent pointers too, 00568 * since they've changed trees. 00569 */ 00570 if (RtlRightChild(P)) RtlParent(RtlRightChild(P)) = P; 00571 if (RtlLeftChild(G)) RtlParent(RtlLeftChild(G)) = G; 00572 00573 /* 00574 * Now we'll shove N all the way to the top. 00575 * Check if G is the root first. 00576 */ 00577 if (RtlIsRoot(G)) 00578 { 00579 /* G doesn't have a parent, so N will become the root! */ 00580 RtlParent(N) = N; 00581 } 00582 else 00583 { 00584 /* G has a parent, so inherit it since we take G's place */ 00585 RtlParent(N) = RtlParent(G); 00586 00587 /* 00588 * Now find out who was referencing G and have it reference 00589 * N instead, since we're taking G's place. 00590 */ 00591 if (RtlIsLeftChild(G)) 00592 { 00593 /* 00594 * G was a left child, so change its parent's left 00595 * child link to point to N now. 00596 */ 00597 RtlLeftChild(RtlParent(G)) = N; 00598 } 00599 else 00600 { 00601 /* 00602 * G was a right child, so change its parent's right 00603 * child link to point to N now. 00604 */ 00605 RtlRightChild(RtlParent(G)) = N; 00606 } 00607 } 00608 00609 /* Now N is on top, so P has become its left child. */ 00610 RtlLeftChild(N) = P; 00611 RtlParent(G) = N; 00612 00613 /* N is on top, P is its left child, so G is right child. */ 00614 RtlRightChild(N) = G; 00615 RtlParent(P) = N; 00616 } 00617 /* "Finally" case: N doesn't have a grandparent => P is root */ 00618 else 00619 { 00620 /* P's right-child becomes N's left child */ 00621 RtlRightChild(P) = RtlLeftChild(N); 00622 00623 /* If it exists, update its parent pointer too */ 00624 if (RtlRightChild(P)) RtlParent(RtlRightChild(P)) = P; 00625 00626 /* Now make N the root, no need to worry about references */ 00627 N->Parent = N; 00628 00629 /* And make P its left child */ 00630 N->LeftChild = P; 00631 P->Parent = N; 00632 } 00633 } 00634 } 00635 00636 /* Return the root entry */ 00637 ASSERT(RtlIsRoot(N)); 00638 return N; 00639 } 00640 00641 /* 00642 * @implemented 00643 */ 00644 PRTL_SPLAY_LINKS 00645 NTAPI 00646 RtlSubtreePredecessor(IN PRTL_SPLAY_LINKS Links) 00647 { 00648 PRTL_SPLAY_LINKS Child; 00649 00650 /* Get the left child */ 00651 Child = RtlLeftChild(Links); 00652 if (!Child) return NULL; 00653 00654 /* Get right-most child */ 00655 while (RtlRightChild(Child)) Child = RtlRightChild(Child); 00656 00657 /* Return it */ 00658 return Child; 00659 } 00660 00661 /* 00662 * @implemented 00663 */ 00664 PRTL_SPLAY_LINKS 00665 NTAPI 00666 RtlSubtreeSuccessor(IN PRTL_SPLAY_LINKS Links) 00667 { 00668 PRTL_SPLAY_LINKS Child; 00669 00670 /* Get the right child */ 00671 Child = RtlRightChild(Links); 00672 if (!Child) return NULL; 00673 00674 /* Get left-most child */ 00675 while (RtlLeftChild(Child)) Child = RtlLeftChild(Child); 00676 00677 /* Return it */ 00678 return Child; 00679 } 00680 00681 /* EOF */ Generated on Sat May 26 2012 04:35:23 for ReactOS by
1.7.6.1
|