Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung 00019 * All rights reserved. 00020 * 00021 * Contributor(s): Joshua Leung (original author) 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 */ 00025 00031 #include "MEM_guardedalloc.h" 00032 00033 #include "BLI_blenlib.h" 00034 #include "BLI_dlrbTree.h" 00035 00036 /* *********************************************** */ 00037 /* Tree API */ 00038 00039 /* Create a new tree, and initialise as necessary */ 00040 DLRBT_Tree *BLI_dlrbTree_new (void) 00041 { 00042 /* just allocate for now */ 00043 return MEM_callocN(sizeof(DLRBT_Tree), "DLRBT_Tree"); 00044 } 00045 00046 /* Just zero out the pointers used */ 00047 void BLI_dlrbTree_init (DLRBT_Tree *tree) 00048 { 00049 if (tree == NULL) 00050 return; 00051 00052 tree->first= tree->last= tree->root= NULL; 00053 } 00054 00055 /* Helper for traversing tree and freeing sub-nodes */ 00056 static void recursive_tree_free_nodes (DLRBT_Node *node) 00057 { 00058 /* sanity check */ 00059 if (node == NULL) 00060 return; 00061 00062 /* free child nodes + subtrees */ 00063 recursive_tree_free_nodes(node->left); 00064 recursive_tree_free_nodes(node->right); 00065 00066 /* free self */ 00067 MEM_freeN(node); 00068 } 00069 00070 /* Free the given tree's data but not the tree itself */ 00071 void BLI_dlrbTree_free (DLRBT_Tree *tree) 00072 { 00073 if (tree == NULL) 00074 return; 00075 00076 /* if the list-base stuff is set, just use that (and assume its set), 00077 * otherwise, we'll need to traverse the tree... 00078 */ 00079 if (tree->first) { 00080 /* free list */ 00081 BLI_freelistN((ListBase *)tree); 00082 } 00083 else { 00084 /* traverse tree, freeing sub-nodes */ 00085 recursive_tree_free_nodes(tree->root); 00086 } 00087 00088 /* clear pointers */ 00089 tree->first= tree->last= tree->root= NULL; 00090 } 00091 00092 /* ------- */ 00093 00094 /* Helper function - used for traversing down the tree from the root to add nodes in order */ 00095 static void linkedlist_sync_add_node (DLRBT_Tree *tree, DLRBT_Node *node) 00096 { 00097 /* sanity checks */ 00098 if ((tree == NULL) || (node == NULL)) 00099 return; 00100 00101 /* add left-node (and its subtree) */ 00102 linkedlist_sync_add_node(tree, node->left); 00103 00104 /* now add self 00105 * - must remove detach from other links first 00106 * (for now, only clear own pointers) 00107 */ 00108 node->prev= node->next= NULL; 00109 BLI_addtail((ListBase *)tree, (Link *)node); 00110 00111 /* finally, add right node (and its subtree) */ 00112 linkedlist_sync_add_node(tree, node->right); 00113 } 00114 00115 /* Make sure the tree's Double-Linked list representation is valid */ 00116 void BLI_dlrbTree_linkedlist_sync (DLRBT_Tree *tree) 00117 { 00118 /* sanity checks */ 00119 if (tree == NULL) 00120 return; 00121 00122 /* clear list-base pointers so that the new list can be added properly */ 00123 tree->first= tree->last= NULL; 00124 00125 /* start adding items from the root */ 00126 linkedlist_sync_add_node(tree, tree->root); 00127 } 00128 00129 /* *********************************************** */ 00130 /* Tree Search Utilities */ 00131 00132 /* Find the node which matches or is the closest to the requested node */ 00133 DLRBT_Node *BLI_dlrbTree_search (DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data) 00134 { 00135 DLRBT_Node *node = (tree) ? tree->root : NULL; 00136 short found= 0; 00137 00138 /* check that there is a comparator to use */ 00139 // TODO: if no comparator is supplied, try using the one supplied with the tree... 00140 if (cmp_cb == NULL) 00141 return NULL; 00142 00143 /* iteratively perform this search */ 00144 while (node && found==0) 00145 { 00146 /* check if traverse further or not 00147 * NOTE: it is assumed that the values will be unit values only 00148 */ 00149 switch (cmp_cb(node, search_data)) { 00150 case -1: /* data less than node */ 00151 if (node->left) 00152 node= node->left; 00153 else 00154 found= 1; 00155 break; 00156 00157 case 1: /* data greater than node */ 00158 if (node->right) 00159 node= node->right; 00160 else 00161 found= 1; 00162 break; 00163 00164 default: /* data equals node */ 00165 found= 1; 00166 break; 00167 } 00168 } 00169 00170 /* return the nearest matching node */ 00171 return node; 00172 } 00173 00174 /* Find the node which exactly matches the required data */ 00175 DLRBT_Node *BLI_dlrbTree_search_exact (DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data) 00176 { 00177 DLRBT_Node *node = (tree) ? tree->root : NULL; 00178 short found= 0; 00179 00180 /* check that there is a comparator to use */ 00181 // TODO: if no comparator is supplied, try using the one supplied with the tree... 00182 if (cmp_cb == NULL) 00183 return NULL; 00184 00185 /* iteratively perform this search */ 00186 while (node && found==0) 00187 { 00188 /* check if traverse further or not 00189 * NOTE: it is assumed that the values will be unit values only 00190 */ 00191 switch (cmp_cb(node, search_data)) { 00192 case -1: /* data less than node */ 00193 if (node->left) 00194 node= node->left; 00195 else 00196 found= -1; 00197 break; 00198 00199 case 1: /* data greater than node */ 00200 if (node->right) 00201 node= node->right; 00202 else 00203 found= -1; 00204 break; 00205 00206 default: /* data equals node */ 00207 found= 1; 00208 break; 00209 } 00210 } 00211 00212 /* return the exactly matching node */ 00213 return (found == 1) ? (node) : (NULL); 00214 } 00215 00216 /* Find the node which occurs immediately before the best matching node */ 00217 DLRBT_Node *BLI_dlrbTree_search_prev (DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data) 00218 { 00219 DLRBT_Node *node; 00220 00221 /* check that there is a comparator to use */ 00222 // TODO: if no comparator is supplied, try using the one supplied with the tree... 00223 if (cmp_cb == NULL) 00224 return NULL; 00225 00226 /* get the node which best matches this description */ 00227 node= BLI_dlrbTree_search(tree, cmp_cb, search_data); 00228 00229 if (node) { 00230 /* if the item we're searching for is greater than the node found, we've found the match */ 00231 if (cmp_cb(node, search_data) > 0) 00232 return node; 00233 00234 /* return the previous node otherwise */ 00235 // NOTE: what happens if there is no previous node? 00236 return node->prev; 00237 } 00238 00239 /* nothing matching was found */ 00240 return NULL; 00241 } 00242 00243 /* Find the node which occurs immediately after the best matching node */ 00244 DLRBT_Node *BLI_dlrbTree_search_next (DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data) 00245 { 00246 DLRBT_Node *node; 00247 00248 /* check that there is a comparator to use */ 00249 // TODO: if no comparator is supplied, try using the one supplied with the tree... 00250 if (cmp_cb == NULL) 00251 return NULL; 00252 00253 /* get the node which best matches this description */ 00254 node= BLI_dlrbTree_search(tree, cmp_cb, search_data); 00255 00256 if (node) { 00257 /* if the item we're searching for is less than the node found, we've found the match */ 00258 if (cmp_cb(node, search_data) < 0) 00259 return node; 00260 00261 /* return the previous node otherwise */ 00262 // NOTE: what happens if there is no previous node? 00263 return node->next; 00264 } 00265 00266 /* nothing matching was found */ 00267 return NULL; 00268 } 00269 00270 00271 /* Check whether there is a node matching the requested node */ 00272 short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data) 00273 { 00274 /* check if an exact search throws up anything... */ 00275 return (BLI_dlrbTree_search_exact(tree, cmp_cb, search_data) != NULL); 00276 } 00277 00278 /* *********************************************** */ 00279 /* Tree Relationships Utilities */ 00280 00281 /* get the 'grandparent' - the parent of the parent - of the given node */ 00282 static DLRBT_Node *get_grandparent (DLRBT_Node *node) 00283 { 00284 if (node && node->parent) 00285 return node->parent->parent; 00286 else 00287 return NULL; 00288 } 00289 00290 /* get the sibling node (e.g. if node is left child of parent, return right child of parent) */ 00291 static DLRBT_Node *get_sibling(DLRBT_Node *node) 00292 { 00293 if (node && node->parent) { 00294 if (node == node->parent->left) 00295 return node->parent->right; 00296 else 00297 return node->parent->left; 00298 } 00299 00300 /* sibling not found */ 00301 return NULL; 00302 } 00303 00304 /* get the 'uncle' - the sibling of the parent - of the given node */ 00305 static DLRBT_Node *get_uncle (DLRBT_Node *node) 00306 { 00307 if (node) 00308 /* return the child of the grandparent which isn't the node's parent */ 00309 return get_sibling(node->parent); 00310 00311 /* uncle not found */ 00312 return NULL; 00313 } 00314 00315 /* *********************************************** */ 00316 /* Tree Rotation Utilities */ 00317 00318 /* make right child of 'root' the new root */ 00319 static void rotate_left (DLRBT_Tree *tree, DLRBT_Node *root) 00320 { 00321 DLRBT_Node **root_slot, *pivot; 00322 00323 /* pivot is simply the root's right child, to become the root's parent */ 00324 pivot= root->right; 00325 if (pivot == NULL) 00326 return; 00327 00328 if (root->parent) { 00329 if (root == root->parent->left) 00330 root_slot= &root->parent->left; 00331 else 00332 root_slot= &root->parent->right; 00333 } 00334 else 00335 root_slot= ((DLRBT_Node**)&tree->root);//&((DLRBT_Node*)tree->root); 00336 00337 /* - pivot's left child becomes root's right child 00338 * - root now becomes pivot's left child 00339 */ 00340 root->right= pivot->left; 00341 if (pivot->left) pivot->left->parent= root; 00342 00343 pivot->left= root; 00344 pivot->parent= root->parent; 00345 root->parent= pivot; 00346 00347 /* make the pivot the new root */ 00348 if (root_slot) 00349 *root_slot= pivot; 00350 } 00351 00352 /* make the left child of the 'root' the new root */ 00353 static void rotate_right (DLRBT_Tree *tree, DLRBT_Node *root) 00354 { 00355 DLRBT_Node **root_slot, *pivot; 00356 00357 /* pivot is simply the root's left child, to become the root's parent */ 00358 pivot= root->left; 00359 if (pivot == NULL) 00360 return; 00361 00362 if (root->parent) { 00363 if (root == root->parent->left) 00364 root_slot= &root->parent->left; 00365 else 00366 root_slot= &root->parent->right; 00367 } 00368 else 00369 root_slot= ((DLRBT_Node**)&tree->root);//&((DLRBT_Node*)tree->root); 00370 00371 /* - pivot's right child becomes root's left child 00372 * - root now becomes pivot's right child 00373 */ 00374 root->left= pivot->right; 00375 if (pivot->right) pivot->right->parent= root; 00376 00377 pivot->right= root; 00378 pivot->parent= root->parent; 00379 root->parent= pivot; 00380 00381 /* make the pivot the new root */ 00382 if (root_slot) 00383 *root_slot= pivot; 00384 } 00385 00386 /* *********************************************** */ 00387 /* Post-Insertion Balancing */ 00388 00389 /* forward defines for insertion checks */ 00390 static void insert_check_1(DLRBT_Tree *tree, DLRBT_Node *node); 00391 static void insert_check_2(DLRBT_Tree *tree, DLRBT_Node *node); 00392 static void insert_check_3(DLRBT_Tree *tree, DLRBT_Node *node); 00393 00394 /* ----- */ 00395 00396 /* W. 1) Root must be black (so that the 2nd-generation can have a black parent) */ 00397 static void insert_check_1 (DLRBT_Tree *tree, DLRBT_Node *node) 00398 { 00399 if (node) { 00400 /* if this is the root, just ensure that it is black */ 00401 if (node->parent == NULL) 00402 node->tree_col= DLRBT_BLACK; 00403 else 00404 insert_check_2(tree, node); 00405 } 00406 } 00407 00408 /* W. 2+3) Parent of node must be black, otherwise recolor and flush */ 00409 static void insert_check_2 (DLRBT_Tree *tree, DLRBT_Node *node) 00410 { 00411 /* if the parent is not black, we need to change that... */ 00412 if (node && node->parent && node->parent->tree_col) { 00413 DLRBT_Node *unc= get_uncle(node); 00414 00415 /* if uncle and parent are both red, need to change them to black and make 00416 * the parent black in order to satisfy the criteria of each node having the 00417 * same number of black nodes to its leaves 00418 */ 00419 if (unc && unc->tree_col) { 00420 DLRBT_Node *gp= get_grandparent(node); 00421 00422 /* make the n-1 generation nodes black */ 00423 node->parent->tree_col= unc->tree_col= DLRBT_BLACK; 00424 00425 /* - make the grandparent red, so that we maintain alternating red/black property 00426 * (it must exist, so no need to check for NULL here), 00427 * - as the grandparent may now cause inconsistencies with the rest of the tree, 00428 * we must flush up the tree and perform checks/rebalancing/repainting, using the 00429 * grandparent as the node of interest 00430 */ 00431 gp->tree_col= DLRBT_RED; 00432 insert_check_1(tree, gp); 00433 } 00434 else { 00435 /* we've got an unbalanced branch going down the grandparent to the parent, 00436 * so need to perform some rotations to re-balance the tree 00437 */ 00438 insert_check_3(tree, node); 00439 } 00440 } 00441 } 00442 00443 /* W. 4+5) Perform rotation on sub-tree containing the 'new' node, then do any */ 00444 static void insert_check_3 (DLRBT_Tree *tree, DLRBT_Node *node) 00445 { 00446 DLRBT_Node *gp= get_grandparent(node); 00447 00448 /* check that grandparent and node->parent exist (jut in case... really shouldn't happen on a good tree) */ 00449 if (node && node->parent && gp) { 00450 /* a left rotation will switch the roles of node and its parent, assuming that 00451 * the parent is the left child of the grandparent... otherwise, rotation direction 00452 * should be swapped 00453 */ 00454 if ((node == node->parent->right) && (node->parent == gp->left)) { 00455 rotate_left(tree, node); 00456 node= node->left; 00457 } 00458 else if ((node == node->parent->left) && (node->parent == gp->right)) { 00459 rotate_right(tree, node); 00460 node= node->right; 00461 } 00462 00463 /* fix old parent's color-tagging, and perform rotation on the old parent in the 00464 * opposite direction if needed for the current situation 00465 * NOTE: in the code above, node pointer is changed to point to the old parent 00466 */ 00467 if (node) { 00468 /* get 'new' grandparent (i.e. grandparent for old-parent (node)) */ 00469 gp= get_grandparent(node); 00470 00471 /* modify the coloring of the grandparent and parent so that they still satisfy the constraints */ 00472 node->parent->tree_col= DLRBT_BLACK; 00473 gp->tree_col= DLRBT_RED; 00474 00475 /* if there are several nodes that all form a left chain, do a right rotation to correct this 00476 * (or a rotation in the opposite direction if they all form a right chain) 00477 */ 00478 if ((node == node->parent->left) && (node->parent == gp->left)) 00479 rotate_right(tree, gp); 00480 else //if ((node == node->parent->right) && (node->parent == gp->right)) 00481 rotate_left(tree, gp); 00482 } 00483 } 00484 } 00485 00486 /* ----- */ 00487 00488 /* Balance the tree after the given element has been added to it 00489 * (using custom code, in the Binary Tree way). 00490 */ 00491 void BLI_dlrbTree_insert (DLRBT_Tree *tree, DLRBT_Node *node) 00492 { 00493 /* sanity checks */ 00494 if ((tree == NULL) || (node == NULL)) 00495 return; 00496 00497 /* firstly, the node we just added should be red by default */ 00498 node->tree_col= DLRBT_RED; 00499 00500 /* start from case 1, an trek through the tail-recursive insertion checks */ 00501 insert_check_1(tree, node); 00502 } 00503 00504 /* ----- */ 00505 00506 /* Add the given data to the tree, and return the node added */ 00507 // NOTE: for duplicates, the update_cb is called (if available), and the existing node is returned 00508 DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, 00509 DLRBT_NAlloc_FP new_cb, DLRBT_NUpdate_FP update_cb, void *data) 00510 { 00511 DLRBT_Node *parNode, *node=NULL; 00512 short new_node = 0; 00513 00514 /* sanity checks */ 00515 if (tree == NULL) 00516 return NULL; 00517 00518 // TODO: if no comparator is supplied, try using the one supplied with the tree... 00519 if (cmp_cb == NULL) 00520 return NULL; 00521 // TODO: if no allocator is supplied, try using the one supplied with the tree... 00522 if (new_cb == NULL) 00523 return NULL; 00524 // TODO: if no updater is supplied, try using the one supplied with the tree... 00525 00526 /* try to find the nearest node to this one */ 00527 parNode= BLI_dlrbTree_search(tree, cmp_cb, data); 00528 00529 /* add new node to the BST in the 'standard way' as appropriate 00530 * NOTE: we do not support duplicates in our tree... 00531 */ 00532 if (parNode) { 00533 /* check how this new node compares with the existing ones 00534 * NOTE: it is assumed that the values will be unit values only 00535 */ 00536 switch (cmp_cb(parNode, data)) { 00537 case -1: /* add new node as left child */ 00538 { 00539 node= new_cb(data); 00540 new_node= 1; 00541 00542 parNode->left= node; 00543 node->parent= parNode; 00544 } 00545 break; 00546 00547 case 1: /* add new node as right child */ 00548 { 00549 node= new_cb(data); 00550 new_node= 1; 00551 00552 parNode->right= node; 00553 node->parent= parNode; 00554 } 00555 break; 00556 00557 default: /* update the duplicate node as appropriate */ 00558 { 00559 if (update_cb) 00560 update_cb(parNode, data); 00561 } 00562 break; 00563 } 00564 } 00565 else { 00566 /* no nodes in the tree yet... add a new node as the root */ 00567 node= new_cb(data); 00568 new_node= 1; 00569 00570 tree->root= node; 00571 } 00572 00573 /* if a new node was added, it should be tagged as red, and then balanced as appropriate */ 00574 if (new_node) { 00575 /* tag this new node as being 'red' */ 00576 node->tree_col= DLRBT_RED; 00577 00578 /* perform BST balancing steps: 00579 * start from case 1, an trek through the tail-recursive insertion checks 00580 */ 00581 insert_check_1(tree, node); 00582 } 00583 00584 /* return the node added */ 00585 return node; 00586 } 00587 00588 /* *********************************************** */ 00589 /* Remove */ 00590 00591 // TODO: this hasn't been coded yet, since this functionality was not needed by the author 00592 00593 /* *********************************************** */