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