Changeset 33 for trunk/src/helpers/tree.c
- Timestamp:
- Feb 7, 2001, 7:30:59 PM (25 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/helpers/tree.c
r21 r33 17 17 * tree sorting/comparison. This implementation is released 18 18 * under the GPL. 19 * 20 * <B>Introduction</B> 21 * 22 * Binary trees are different from linked lists in that items 23 * are not simply linked sequentially, but instead put into 24 * a tree-like structure. 25 * 26 * For this, the functions here use the TREE structure. You can 27 * easily see that this has the "left" and "right" members, 28 * which make up the tree. 29 * 30 * In addition, each tree has a "tree root" item, from which all 31 * other tree nodes can be reached by following the "left" and 32 * "right" pointers. 33 * 34 * Per definition, in our trees, if you follow the "left" pointer, 35 * you will reach an item which is "greater than" the current node. 36 * Reversely, following the "right" pointer will lead you to a 37 * node which is "less than" the current node. 38 * 39 * The implementation here has the following characteristics: 40 * 41 * -- We have "binary" trees. That is, there are only "left" and 42 * "right" pointers. 43 * 44 * -- The tree is always "balanced". The tree gets completely 45 * reordered when items are added/removed to ensure that 46 * all paths through the tree are approximately the same 47 * length. This avoids the "worst case" scenario that some 48 * paths grow terribly long while others remain short, which 49 * can make searching very inefficient. 50 * 51 * -- The tree nodes are marked as either "red" or "black", which 52 * is an algorithm to allow the implementation of 2-3-4 trees 53 * using a binary tree only. I don't fully understand how this 54 * works, but essentially, "red" nodes represent a 3 or 4 node, 55 * while "black" nodes are plain binary nodes. 56 * 57 * As much as I understand about all this, red-black balanced 58 * binary trees are the most efficient tree algorithm known to 59 * mankind. As long as you are sure that trees are more efficient 60 * in your situation than a linked list in the first place (see 61 * below for comparisons), use the functions in here. 19 62 * 20 63 * <B>Using binary trees</B> … … 31 74 * for a sample. 32 75 * 33 * Each TREE node does not only contain data, but also an34 * "id" field. The order of nodes in the tree is determined35 * by calling a node comparison function provided by the caller36 * (which you must write). This takes two "id" values and must37 * return:38 *39 + 0: id1 == id240 + -1: id1 < id241 + +1: id1 > id242 *43 76 * Initialize the root of the tree with treeInit(). Then 44 77 * add nodes to the tree with treeInsertID() and remove nodes … … 48 81 * root with TREE_NULL. 49 82 * 83 * Most functions in here come in two flavors. 84 * 85 * -- You can provide a comparison function and use the "Node" 86 * flavors of these functions. This is useful, for example, 87 * if you are storing strings. You can then write a short 88 * comparison function which does a strcmp() on the data 89 * of tree nodes. 90 * 91 * The order of nodes in the tree is determined by calling a 92 * node comparison function provided by the caller 93 * (which you must write). This takes two TREE pointers and 94 * must return: 95 * 96 + 0: tree1 == tree2 97 + -1: tree1 < tree2 98 + +1: tree1 > tree2 99 * 100 * -- The "ID" functions (e.g. treeInsertID) do not require 101 * a comparison function, but will use the "id" member of 102 * the TREE structure instead. If this flavor is used, an 103 * internal comparison function is used for comparing the 104 * "id" fields, which are plain ULONGs. 105 * 106 * <B>Trees vs. linked lists</B> 107 * 50 108 * Compared to linked lists (as implemented by linklist.c), 51 109 * trees allow for much faster searching. 52 110 * 53 * Assuming a linked list contains N items, then searching the54 * li st for an item will take an average of N/2 comparisons111 * Assuming a linked list contains N items, then searching a 112 * linked list for an item will take an average of N/2 comparisons 55 113 * and even N comparisons if the item cannot be found (unless 56 114 * you keep the list sorted, but linklist.c doesn't do this). … … 72 130 * nodes because the tree is always sorted. 73 131 * 74 * -- You must always supply a comparison function to allow the75 * tree functions to sort the tree.132 * -- If you are not using the "ID" flavors, you must supply a 133 * comparison function to allow the tree functions to sort the tree. 76 134 * 77 135 * -- As opposed to a LISTNODE, the TREE structure (which … … 134 192 135 193 /* 194 * fnCompareIDs: 195 * 196 *added V0.9.9 (2000-02-06) [umoeller] 197 */ 198 199 int fnCompareIDs(unsigned long id1, unsigned long id2) 200 { 201 if (id1 < id2) 202 return -1; 203 if (id1 > id2) 204 return +1; 205 return (0); 206 } 207 208 /* 136 209 *@@ treeInsertID: 137 210 * inserts a node into an existing tree. … … 169 242 + treeInsertID(&TreeRoot, 170 243 + (TREE*)pTreeItem, 171 + fnCompare, // your comparison function172 244 + FALSE); 173 245 * … … 179 251 * returned if a tree item with the specified ID already 180 252 * exists. 253 * 254 *@@changed V0.9.9 (2000-02-06) [umoeller]: removed comparison func 181 255 */ 182 256 183 257 int treeInsertID(TREE **root, // in: root of tree 184 258 TREE *tree, // in: new tree node 185 FNTREE_COMPARE_IDS *comp, // in: comparison function186 259 BOOL fAllowDuplicates) // in: whether duplicates with the same ID are allowed 187 260 { … … 198 271 { 199 272 parent = current; 200 last_comp = comp(tree->id, current->id);273 last_comp = fnCompareIDs(tree->id, current->id); 201 274 switch (last_comp) 202 275 { … … 211 284 } 212 285 213 // set up new node214 ((TREE *)tree)->parent = parent;215 ((TREE *)tree)->left = TREE_NULL;216 ((TREE *)tree)->right = TREE_NULL;217 ((TREE *)tree)->colour = RED;286 // set up new node 287 ((TREE*)tree)->parent = parent; 288 ((TREE*)tree)->left = TREE_NULL; 289 ((TREE*)tree)->right = TREE_NULL; 290 ((TREE*)tree)->colour = RED; 218 291 219 292 // insert node in tree … … 268 341 } 269 342 270 // set up new node271 ((TREE *)tree)->parent = parent;272 ((TREE *)tree)->left = TREE_NULL;273 ((TREE *)tree)->right = TREE_NULL;274 ((TREE *)tree)->colour = RED;343 // set up new node 344 ((TREE*)tree)->parent = parent; 345 ((TREE*)tree)->left = TREE_NULL; 346 ((TREE*)tree)->right = TREE_NULL; 347 ((TREE*)tree)->colour = RED; 275 348 276 349 // insert node in tree … … 464 537 return TREE_INVALID_NODE; 465 538 466 if ( (((TREE *)tree)->left == TREE_NULL)467 || (((TREE *)tree)->right == TREE_NULL)539 if ( (((TREE*)tree)->left == TREE_NULL) 540 || (((TREE*)tree)->right == TREE_NULL) 468 541 ) 469 542 // descendent has a TREE_NULL node as a child … … 472 545 { 473 546 // find tree successor with a TREE_NULL node as a child 474 descendent = ((TREE *)tree)->right;547 descendent = ((TREE*)tree)->right; 475 548 while (descendent->left != TREE_NULL) 476 549 descendent = descendent->left; … … 499 572 500 573 if (descendent != (TREE *) tree) 501 {574 { 502 575 // Conceptually what we are doing here is moving the data from 503 576 // descendent to tree. In fact we do this by linking descendent 504 577 // into the structure in the place of tree. 505 descendent->left = ((TREE *)tree)->left;506 descendent->right = ((TREE *)tree)->right;507 descendent->parent = ((TREE *)tree)->parent;508 descendent->colour = ((TREE *)tree)->colour;578 descendent->left = ((TREE*)tree)->left; 579 descendent->right = ((TREE*)tree)->right; 580 descendent->parent = ((TREE*)tree)->parent; 581 descendent->colour = ((TREE*)tree)->colour; 509 582 510 583 if (descendent->parent) 511 {584 { 512 585 if (tree == descendent->parent->left) 513 586 descendent->parent->left = descendent; 514 587 else 515 588 descendent->parent->right = descendent; 516 }589 } 517 590 else 518 591 *root = descendent; … … 618 691 *@@ treeFindEQID: 619 692 * finds a node with ID exactly matching that provided. 620 * To find a tree node, your comparison function must621 * compare the tree node IDs.622 693 */ 623 694 624 695 void* treeFindEQID(TREE **root, 625 unsigned long id, 626 FNTREE_COMPARE_IDS *comp) 696 unsigned long id) 627 697 { 628 698 TREE … … 632 702 found = NULL; 633 703 while (current != TREE_NULL) 634 switch ( comp(current->id, id))704 switch (fnCompareIDs(current->id, id)) 635 705 { 636 706 case -1: current = current->right; break; … … 651 721 652 722 void* treeFindGEID(TREE **root, 653 unsigned long idFind, 654 FNTREE_COMPARE_IDS *comp) 723 unsigned long idFind) 655 724 { 656 725 TREE … … 660 729 found = NULL; 661 730 while (current != TREE_NULL) 662 switch ( comp(current->id, idFind))731 switch (fnCompareIDs(current->id, idFind)) 663 732 { 664 733 case -1: current = current->right; break; … … 873 942 { 874 943 process(tree, pUser); 875 treeTraverse (((TREE *)tree)->left, process, pUser, method);876 treeTraverse (((TREE *)tree)->right, process, pUser, method);944 treeTraverse (((TREE*)tree)->left, process, pUser, method); 945 treeTraverse (((TREE*)tree)->right, process, pUser, method); 877 946 } 878 947 else if (method == 2) 879 948 { 880 treeTraverse (((TREE *)tree)->left, process, pUser, method);881 treeTraverse (((TREE *)tree)->right, process, pUser, method);949 treeTraverse (((TREE*)tree)->left, process, pUser, method); 950 treeTraverse (((TREE*)tree)->right, process, pUser, method); 882 951 process(tree, pUser); 883 952 } 884 953 else 885 954 { 886 treeTraverse (((TREE *)tree)->left, process, pUser, method);955 treeTraverse (((TREE*)tree)->left, process, pUser, method); 887 956 process(tree, pUser); 888 treeTraverse (((TREE *)tree)->right, process, pUser, method);957 treeTraverse (((TREE*)tree)->right, process, pUser, method); 889 958 } 890 959 }
Note:
See TracChangeset
for help on using the changeset viewer.