| 1 |  | 
|---|
| 2 | /* | 
|---|
| 3 | *@@sourcefile tree.c: | 
|---|
| 4 | *      contains helper functions for maintaining 'Red-Black' balanced | 
|---|
| 5 | *      binary trees. | 
|---|
| 6 | * | 
|---|
| 7 | *      Usage: All C programs; not OS/2-specific. | 
|---|
| 8 | * | 
|---|
| 9 | *      Function prefixes (new with V0.81): | 
|---|
| 10 | *      --  tree*    tree helper functions | 
|---|
| 11 | * | 
|---|
| 12 | *      <B>Introduction</B> | 
|---|
| 13 | * | 
|---|
| 14 | *      While linked lists have "next" and "previous" pointers (which | 
|---|
| 15 | *      makes them one-dimensional), trees have a two-dimensional layout: | 
|---|
| 16 | *      each tree node has one "parent" and two "children" which are | 
|---|
| 17 | *      called "left" and "right". The "left" pointer will always lead | 
|---|
| 18 | *      to a tree node that is "less than" its parent node, while the | 
|---|
| 19 | *      "right" pointer will lead to a node that is "greater than" | 
|---|
| 20 | *      its parent. What is considered "less" or "greater" for sorting | 
|---|
| 21 | *      is determined by a comparison callback to be supplied by the | 
|---|
| 22 | *      tree functions' caller. The "leafs" of the tree will have | 
|---|
| 23 | *      null left and right pointers. | 
|---|
| 24 | * | 
|---|
| 25 | *      For this, the functions here use the TREE structure. The most | 
|---|
| 26 | *      important member here is the "ulKey" field which is used for | 
|---|
| 27 | *      sorting (passed to the compare callbacks). Since the tree | 
|---|
| 28 | *      functions do no memory allocation, the caller can easily | 
|---|
| 29 | *      use an extended TREE structure with additional fields as | 
|---|
| 30 | *      long as the first member is the TREE structure. See below. | 
|---|
| 31 | * | 
|---|
| 32 | *      Each tree must have a "root" item, from which all other tree | 
|---|
| 33 | *      nodes can eventually be reached by following the "left" and | 
|---|
| 34 | *      "right" pointers. The root node is the only node whose | 
|---|
| 35 | *      parent is null. | 
|---|
| 36 | * | 
|---|
| 37 | *      <B>Trees vs. linked lists</B> | 
|---|
| 38 | * | 
|---|
| 39 | *      Compared to linked lists (as implemented by linklist.c), | 
|---|
| 40 | *      trees allow for much faster searching, since they are | 
|---|
| 41 | *      always sorted. | 
|---|
| 42 | * | 
|---|
| 43 | *      Take an array of numbers, and assume you'd need to find | 
|---|
| 44 | *      the array node with the specified number. | 
|---|
| 45 | * | 
|---|
| 46 | *      With a (sorted) linked list, this would look like: | 
|---|
| 47 | * | 
|---|
| 48 | +          4  -->  7  -->  16  -->  20  -->  37  -->  38  -->  43 | 
|---|
| 49 | * | 
|---|
| 50 | *      Searching for "43" would need 6 iterations. | 
|---|
| 51 | * | 
|---|
| 52 | *      With a binary tree, this would instead look like: | 
|---|
| 53 | * | 
|---|
| 54 | +                       20 | 
|---|
| 55 | +                     /    \ | 
|---|
| 56 | +                    7      38 | 
|---|
| 57 | +                   / \    /  \ | 
|---|
| 58 | +                  4  16  37   43 | 
|---|
| 59 | +                 / \ / \ / \ / \ | 
|---|
| 60 | * | 
|---|
| 61 | *      Searching for "43" would need 2 iterations only. | 
|---|
| 62 | * | 
|---|
| 63 | *      Assuming a linked list contains N items, then searching a | 
|---|
| 64 | *      linked list for an item will take an average of N/2 comparisons | 
|---|
| 65 | *      and even N comparisons if the item cannot be found (unless | 
|---|
| 66 | *      you keep the list sorted, but linklist.c doesn't do this). | 
|---|
| 67 | * | 
|---|
| 68 | *      According to "Algorithms in C", a search in a balanced | 
|---|
| 69 | *      "red-black" binary tree takes about lg N comparisons on | 
|---|
| 70 | *      average, and insertions take less than one rotation on | 
|---|
| 71 | *      average. | 
|---|
| 72 | * | 
|---|
| 73 | *      Differences compared to linklist.c: | 
|---|
| 74 | * | 
|---|
| 75 | *      -- A tree is always sorted. | 
|---|
| 76 | * | 
|---|
| 77 | *      -- Trees are considerably slower when inserting and removing | 
|---|
| 78 | *         nodes because the tree has to be rebalanced every time | 
|---|
| 79 | *         a node changes. By contrast, trees are much faster finding | 
|---|
| 80 | *         nodes because the tree is always sorted. | 
|---|
| 81 | * | 
|---|
| 82 | *      -- As opposed to a LISTNODE, the TREE structure (which | 
|---|
| 83 | *         represents a tree node) does not contain a data pointer, | 
|---|
| 84 | *         as said above. The caller must do all memory management. | 
|---|
| 85 | * | 
|---|
| 86 | *      <B>Background</B> | 
|---|
| 87 | * | 
|---|
| 88 | *      Now, a "red-black balanced binary tree" means the following: | 
|---|
| 89 | * | 
|---|
| 90 | *      -- We have "binary" trees. That is, there are only "left" and | 
|---|
| 91 | *         "right" pointers. (Other algorithms allow tree nodes to | 
|---|
| 92 | *         have more than two children, but binary trees are usually | 
|---|
| 93 | *         more efficient.) | 
|---|
| 94 | * | 
|---|
| 95 | *      -- The tree is always "balanced". The tree gets reordered | 
|---|
| 96 | *         when items are added/removed to ensure that all paths | 
|---|
| 97 | *         through the tree are approximately the same length. | 
|---|
| 98 | *         This avoids the "worst case" scenario that some paths | 
|---|
| 99 | *         grow terribly long while others remain short ("degenerated" | 
|---|
| 100 | *         trees), which can make searching very inefficient: | 
|---|
| 101 | * | 
|---|
| 102 | +                  4 | 
|---|
| 103 | +                 / \ | 
|---|
| 104 | +                    7 | 
|---|
| 105 | +                   / \ | 
|---|
| 106 | +                      16 | 
|---|
| 107 | +                     / \ | 
|---|
| 108 | +                        20 | 
|---|
| 109 | +                       / \ | 
|---|
| 110 | +                          37 | 
|---|
| 111 | +                         / \ | 
|---|
| 112 | +                            43 | 
|---|
| 113 | +                           /  \ | 
|---|
| 114 | * | 
|---|
| 115 | *      -- Fully balanced trees can be quite expensive because on | 
|---|
| 116 | *         every insertion or deletion, the tree nodes must be rotated. | 
|---|
| 117 | *         By contrast, "Red-black" binary balanced trees contain | 
|---|
| 118 | *         an additional bit in each node which marks the node as | 
|---|
| 119 | *         either red or black. This bit is used only for efficient | 
|---|
| 120 | *         rebalancing when inserting or deleting nodes. | 
|---|
| 121 | * | 
|---|
| 122 | *         I don't fully understand why this works, but if you really | 
|---|
| 123 | *         care, this is explained at | 
|---|
| 124 | *         "http://www.eli.sdsu.edu/courses/fall96/cs660/notes/redBlack/redBlack.html". | 
|---|
| 125 | * | 
|---|
| 126 | *      In other words, as opposed to regular binary trees, RB trees | 
|---|
| 127 | *      are not _fully_ balanced, but they are _mostly_ balanced. With | 
|---|
| 128 | *      respect to efficiency, RB trees are thus a good compromise: | 
|---|
| 129 | * | 
|---|
| 130 | *      -- Completely unbalanced trees are efficient when inserting, | 
|---|
| 131 | *         but can have a terrible worst case when searching. | 
|---|
| 132 | * | 
|---|
| 133 | *      -- RB trees are still acceptably efficient when inserting | 
|---|
| 134 | *         and quite efficient when searching. | 
|---|
| 135 | *         A RB tree with n internal nodes has a height of at most | 
|---|
| 136 | *         2lg(n+1). Both average and worst-case search time is O(lg n). | 
|---|
| 137 | * | 
|---|
| 138 | *      -- Fully balanced binary trees are inefficient when inserting | 
|---|
| 139 | *         but most efficient when searching. | 
|---|
| 140 | * | 
|---|
| 141 | *      So as long as you are sure that trees are more efficient | 
|---|
| 142 | *      in your situation than a linked list in the first place, use | 
|---|
| 143 | *      these RB trees instead of linked lists. | 
|---|
| 144 | * | 
|---|
| 145 | *      <B>Using binary trees</B> | 
|---|
| 146 | * | 
|---|
| 147 | *      You can use any structure as elements in a tree, provided | 
|---|
| 148 | *      that the first member in the structure is a TREE structure | 
|---|
| 149 | *      (i.e. it has the left, right, parent, and color members). | 
|---|
| 150 | *      Each TREE node has a ulKey field which is used for | 
|---|
| 151 | *      comparing tree nodes and thus determines the location of | 
|---|
| 152 | *      the node in the tree. | 
|---|
| 153 | * | 
|---|
| 154 | *      The tree functions don't care what follows in each TREE | 
|---|
| 155 | *      node since they do not manage any memory themselves. | 
|---|
| 156 | *      So the implementation here is slightly different from the | 
|---|
| 157 | *      linked lists in linklist.c, because the LISTNODE structs | 
|---|
| 158 | *      only have pointers to the data. By contrast, the TREE structs | 
|---|
| 159 | *      are expected to contain the data themselves. | 
|---|
| 160 | * | 
|---|
| 161 | *      Initialize the root of the tree with treeInit(). Then | 
|---|
| 162 | *      add nodes to the tree with treeInsert() and remove nodes | 
|---|
| 163 | *      with treeDelete(). See below for a sample. | 
|---|
| 164 | * | 
|---|
| 165 | *      You can test whether a tree is empty by comparing its | 
|---|
| 166 | *      root with LEAF. | 
|---|
| 167 | * | 
|---|
| 168 | *      For most tree* functions, you must specify a comparison | 
|---|
| 169 | *      function which will always receive two "key" parameters | 
|---|
| 170 | *      to compare. This must be declared as | 
|---|
| 171 | + | 
|---|
| 172 | +          int TREEENTRY fnCompare(ULONG ul1, ULONG ul2); | 
|---|
| 173 | * | 
|---|
| 174 | *      This will receive two TREE.ulKey members (whose meaning | 
|---|
| 175 | *      is defined by your implementation) and must return | 
|---|
| 176 | * | 
|---|
| 177 | *      -- something < 0: ul1 < ul2 | 
|---|
| 178 | *      -- 0: ul1 == ul2 | 
|---|
| 179 | *      -- something > 1: ul1 > ul2 | 
|---|
| 180 | * | 
|---|
| 181 | *      <B>Example</B> | 
|---|
| 182 | * | 
|---|
| 183 | *      A good example where trees are efficient would be the | 
|---|
| 184 | *      case where you have "keyword=value" string pairs and | 
|---|
| 185 | *      you frequently need to search for "keyword" to find | 
|---|
| 186 | *      a "value". So "keyword" would be an ideal candidate for | 
|---|
| 187 | *      the TREE.key field. | 
|---|
| 188 | * | 
|---|
| 189 | *      You'd then define your own tree nodes like this: | 
|---|
| 190 | * | 
|---|
| 191 | +          typedef struct _MYTREENODE | 
|---|
| 192 | +          { | 
|---|
| 193 | +              TREE        Tree;       // regular tree node, which has | 
|---|
| 194 | +                                      // the ULONG "key" field; we'd | 
|---|
| 195 | +                                      // use this as a const char* | 
|---|
| 196 | +                                      // pointer to the keyword string | 
|---|
| 197 | +              // here come the additional fields | 
|---|
| 198 | +              // (whatever you need for your data) | 
|---|
| 199 | +              const char  *pcszValue; | 
|---|
| 200 | + | 
|---|
| 201 | +          } MYTREENODE, *PMYTREENODE; | 
|---|
| 202 | * | 
|---|
| 203 | *      Initialize the tree root: | 
|---|
| 204 | * | 
|---|
| 205 | +          TREE *root; | 
|---|
| 206 | +          treeInit(&root); | 
|---|
| 207 | * | 
|---|
| 208 | *      To add a new "keyword=value" pair, do this: | 
|---|
| 209 | * | 
|---|
| 210 | +          PMYTREENODE AddNode(TREE **root, | 
|---|
| 211 | +                              const char *pcszKeyword, | 
|---|
| 212 | +                              const char *pcszValue) | 
|---|
| 213 | +          { | 
|---|
| 214 | +              PMYTREENODE p = (PMYTREENODE)malloc(sizeof(MYTREENODE)); | 
|---|
| 215 | +              p.Tree.ulKey = (ULONG)pcszKeyword; | 
|---|
| 216 | +              p.pcszValue = pcszValue; | 
|---|
| 217 | +              treeInsert(root,                // tree's root | 
|---|
| 218 | +                         p,                   // new tree node | 
|---|
| 219 | +                         fnCompare);          // comparison func | 
|---|
| 220 | +              return (p); | 
|---|
| 221 | +          } | 
|---|
| 222 | * | 
|---|
| 223 | *      Your comparison func receives two ulKey values to compare, | 
|---|
| 224 | *      which in this case would be the typecast string pointers: | 
|---|
| 225 | * | 
|---|
| 226 | +          int TREEENTRY fnCompare(ULONG ul1, ULONG ul2) | 
|---|
| 227 | +          { | 
|---|
| 228 | +              return (strcmp((const char*)ul1, | 
|---|
| 229 | +                             (const char*)ul2)); | 
|---|
| 230 | +          } | 
|---|
| 231 | * | 
|---|
| 232 | *      You can then use treeFind to very quickly find a node | 
|---|
| 233 | *      with a specified ulKey member. | 
|---|
| 234 | * | 
|---|
| 235 | *      This file was new with V0.9.5 (2000-09-29) [umoeller]. | 
|---|
| 236 | *      With V0.9.13, all the code has been replaced with the public | 
|---|
| 237 | *      domain code found at http://epaperpress.com/sortsearch/index.html | 
|---|
| 238 | *      ("A compact guide to searching and sorting") by Thomas Niemann. | 
|---|
| 239 | *      The old implementation from the Standard Function Library (SFL) | 
|---|
| 240 | *      turned out to be buggy for large trees (more than 100 nodes). | 
|---|
| 241 | * | 
|---|
| 242 | *@@added V0.9.5 (2000-09-29) [umoeller] | 
|---|
| 243 | *@@header "helpers\tree.h" | 
|---|
| 244 | */ | 
|---|
| 245 |  | 
|---|
| 246 | /* | 
|---|
| 247 | *      Original coding by Thomas Niemann, placed in the public domain | 
|---|
| 248 | *      (see http://epaperpress.com/sortsearch/index.html). | 
|---|
| 249 | * | 
|---|
| 250 | *      This implementation Copyright (C) 2001 Ulrich Mller. | 
|---|
| 251 | *      This file is part of the "XWorkplace helpers" source package. | 
|---|
| 252 | *      This is free software; you can redistribute it and/or modify | 
|---|
| 253 | *      it under the terms of the GNU General Public License as published | 
|---|
| 254 | *      by the Free Software Foundation, in version 2 as it comes in the | 
|---|
| 255 | *      "COPYING" file of the XWorkplace main distribution. | 
|---|
| 256 | *      This program is distributed in the hope that it will be useful, | 
|---|
| 257 | *      but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 258 | *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 259 | *      GNU General Public License for more details. | 
|---|
| 260 | */ | 
|---|
| 261 |  | 
|---|
| 262 | /* | 
|---|
| 263 | *@@category: Helpers\C helpers\Red-black balanced binary trees | 
|---|
| 264 | *      See tree.c. | 
|---|
| 265 | */ | 
|---|
| 266 |  | 
|---|
| 267 | #include "setup.h" | 
|---|
| 268 | #include "helpers\tree.h" | 
|---|
| 269 |  | 
|---|
| 270 | #define LEAF &sentinel           // all leafs are sentinels | 
|---|
| 271 | STATIC TREE sentinel = { LEAF, LEAF, 0, BLACK}; | 
|---|
| 272 |  | 
|---|
| 273 | /* | 
|---|
| 274 | A binary search tree is a red-black tree if: | 
|---|
| 275 |  | 
|---|
| 276 | 1. Every node is either red or black. | 
|---|
| 277 | 2. Every leaf (nil) is black. | 
|---|
| 278 | 3. If a node is red, then both its children are black. | 
|---|
| 279 | 4. Every simple path from a node to a descendant leaf contains the same | 
|---|
| 280 | number of black nodes. | 
|---|
| 281 | */ | 
|---|
| 282 |  | 
|---|
| 283 | /* | 
|---|
| 284 | *@@ treeInit: | 
|---|
| 285 | *      initializes the root of a tree. | 
|---|
| 286 | * | 
|---|
| 287 | *      If (plCount != NULL), *plCount is set to null also. | 
|---|
| 288 | *      This same plCount pointer can then be passed to | 
|---|
| 289 | *      treeInsert and treeDelete also to automatically | 
|---|
| 290 | *      maintain a tree item count. | 
|---|
| 291 | * | 
|---|
| 292 | *@@changed V0.9.16 (2001-10-19) [umoeller]: added plCount | 
|---|
| 293 | */ | 
|---|
| 294 |  | 
|---|
| 295 | void treeInit(TREE **root, | 
|---|
| 296 | PLONG plCount)            // out: tree item count, set to 0 (ptr can be NULL) | 
|---|
| 297 | { | 
|---|
| 298 | *root = LEAF; | 
|---|
| 299 |  | 
|---|
| 300 | if (plCount) | 
|---|
| 301 | *plCount = 0;       // V0.9.16 (2001-10-19) [umoeller] | 
|---|
| 302 | } | 
|---|
| 303 |  | 
|---|
| 304 | /* | 
|---|
| 305 | *@@ treeCompareKeys: | 
|---|
| 306 | *      standard comparison func if the TREE.ulKey | 
|---|
| 307 | *      field really is a ULONG. | 
|---|
| 308 | */ | 
|---|
| 309 |  | 
|---|
| 310 | int TREEENTRY treeCompareKeys(unsigned long  ul1, unsigned long ul2) | 
|---|
| 311 | { | 
|---|
| 312 | if (ul1 < ul2) | 
|---|
| 313 | return -1; | 
|---|
| 314 |  | 
|---|
| 315 | if (ul1 > ul2) | 
|---|
| 316 | return +1; | 
|---|
| 317 |  | 
|---|
| 318 | return 0; | 
|---|
| 319 | } | 
|---|
| 320 |  | 
|---|
| 321 | /* | 
|---|
| 322 | *@@ treeCompareStrings: | 
|---|
| 323 | *      standard comparison func if the TREE.ulKey | 
|---|
| 324 | *      field really is a string pointer (PCSZ). | 
|---|
| 325 | * | 
|---|
| 326 | *      This runs strcmp internally, but can handle | 
|---|
| 327 | *      NULL pointers without crashing. | 
|---|
| 328 | * | 
|---|
| 329 | *@@added V0.9.16 (2001-09-29) [umoeller] | 
|---|
| 330 | */ | 
|---|
| 331 |  | 
|---|
| 332 | int TREEENTRY treeCompareStrings(unsigned long  ul1, unsigned long ul2) | 
|---|
| 333 | { | 
|---|
| 334 | #define p1 (const char*)(ul1) | 
|---|
| 335 | #define p2 (const char*)(ul2) | 
|---|
| 336 |  | 
|---|
| 337 | if (p1 && p2) | 
|---|
| 338 | { | 
|---|
| 339 | int i = strcmp(p1, p2); | 
|---|
| 340 | if (i < 0) | 
|---|
| 341 | return -1; | 
|---|
| 342 | if (i > 0) | 
|---|
| 343 | return +1; | 
|---|
| 344 | } | 
|---|
| 345 | else if (p1) | 
|---|
| 346 | // but p2 is NULL: p1 greater than p2 then | 
|---|
| 347 | return +1; | 
|---|
| 348 | else if (p2) | 
|---|
| 349 | // but p1 is NULL: p1 less than p2 then | 
|---|
| 350 | return -1; | 
|---|
| 351 |  | 
|---|
| 352 | // return 0 if strcmp returned 0 above or both strings are NULL | 
|---|
| 353 | return 0; | 
|---|
| 354 | } | 
|---|
| 355 |  | 
|---|
| 356 | /* | 
|---|
| 357 | *@@ rotateLeft: | 
|---|
| 358 | *      private function during rebalancing. | 
|---|
| 359 | */ | 
|---|
| 360 |  | 
|---|
| 361 | STATIC void rotateLeft(TREE **root, | 
|---|
| 362 | TREE *x) | 
|---|
| 363 | { | 
|---|
| 364 | // rotate node x to left | 
|---|
| 365 |  | 
|---|
| 366 | TREE *y = x->right; | 
|---|
| 367 |  | 
|---|
| 368 | // establish x->right link | 
|---|
| 369 | x->right = y->left; | 
|---|
| 370 | if (y->left != LEAF) | 
|---|
| 371 | y->left->parent = x; | 
|---|
| 372 |  | 
|---|
| 373 | // establish y->parent link | 
|---|
| 374 | if (y != LEAF) | 
|---|
| 375 | y->parent = x->parent; | 
|---|
| 376 |  | 
|---|
| 377 | if (x->parent) | 
|---|
| 378 | { | 
|---|
| 379 | if (x == x->parent->left) | 
|---|
| 380 | x->parent->left = y; | 
|---|
| 381 | else | 
|---|
| 382 | x->parent->right = y; | 
|---|
| 383 | } | 
|---|
| 384 | else | 
|---|
| 385 | *root = y; | 
|---|
| 386 |  | 
|---|
| 387 | // link x and y | 
|---|
| 388 | y->left = x; | 
|---|
| 389 | if (x != LEAF) | 
|---|
| 390 | x->parent = y; | 
|---|
| 391 | } | 
|---|
| 392 |  | 
|---|
| 393 | /* | 
|---|
| 394 | *@@ rotateRight: | 
|---|
| 395 | *      private function during rebalancing. | 
|---|
| 396 | */ | 
|---|
| 397 |  | 
|---|
| 398 | STATIC void rotateRight(TREE **root, | 
|---|
| 399 | TREE *x) | 
|---|
| 400 | { | 
|---|
| 401 | // rotate node x to right | 
|---|
| 402 |  | 
|---|
| 403 | TREE *y = x->left; | 
|---|
| 404 |  | 
|---|
| 405 | // establish x->left link | 
|---|
| 406 | x->left = y->right; | 
|---|
| 407 | if (y->right != LEAF) | 
|---|
| 408 | y->right->parent = x; | 
|---|
| 409 |  | 
|---|
| 410 | // establish y->parent link | 
|---|
| 411 | if (y != LEAF) | 
|---|
| 412 | y->parent = x->parent; | 
|---|
| 413 |  | 
|---|
| 414 | if (x->parent) | 
|---|
| 415 | { | 
|---|
| 416 | if (x == x->parent->right) | 
|---|
| 417 | x->parent->right = y; | 
|---|
| 418 | else | 
|---|
| 419 | x->parent->left = y; | 
|---|
| 420 | } | 
|---|
| 421 | else | 
|---|
| 422 | *root = y; | 
|---|
| 423 |  | 
|---|
| 424 | // link x and y | 
|---|
| 425 | y->right = x; | 
|---|
| 426 | if (x != LEAF) | 
|---|
| 427 | x->parent = y; | 
|---|
| 428 | } | 
|---|
| 429 |  | 
|---|
| 430 | /* | 
|---|
| 431 | *@@ insertFixup: | 
|---|
| 432 | *      private function during rebalancing. | 
|---|
| 433 | */ | 
|---|
| 434 |  | 
|---|
| 435 | STATIC void insertFixup(TREE **root, | 
|---|
| 436 | TREE *x) | 
|---|
| 437 | { | 
|---|
| 438 | // check Red-Black properties | 
|---|
| 439 | while (    x != *root | 
|---|
| 440 | && x->parent->color == RED | 
|---|
| 441 | ) | 
|---|
| 442 | { | 
|---|
| 443 | // we have a violation | 
|---|
| 444 | if (x->parent == x->parent->parent->left) | 
|---|
| 445 | { | 
|---|
| 446 | TREE *y = x->parent->parent->right; | 
|---|
| 447 | if (y->color == RED) | 
|---|
| 448 | { | 
|---|
| 449 | // uncle is RED | 
|---|
| 450 | x->parent->color = BLACK; | 
|---|
| 451 | y->color = BLACK; | 
|---|
| 452 | x->parent->parent->color = RED; | 
|---|
| 453 | x = x->parent->parent; | 
|---|
| 454 | } | 
|---|
| 455 | else | 
|---|
| 456 | { | 
|---|
| 457 | // uncle is BLACK | 
|---|
| 458 | if (x == x->parent->right) | 
|---|
| 459 | { | 
|---|
| 460 | // make x a left child | 
|---|
| 461 | x = x->parent; | 
|---|
| 462 | rotateLeft(root, | 
|---|
| 463 | x); | 
|---|
| 464 | } | 
|---|
| 465 |  | 
|---|
| 466 | // recolor and rotate | 
|---|
| 467 | x->parent->color = BLACK; | 
|---|
| 468 | x->parent->parent->color = RED; | 
|---|
| 469 | rotateRight(root, | 
|---|
| 470 | x->parent->parent); | 
|---|
| 471 | } | 
|---|
| 472 | } | 
|---|
| 473 | else | 
|---|
| 474 | { | 
|---|
| 475 | // mirror image of above code | 
|---|
| 476 | TREE *y = x->parent->parent->left; | 
|---|
| 477 | if (y->color == RED) | 
|---|
| 478 | { | 
|---|
| 479 | // uncle is RED | 
|---|
| 480 | x->parent->color = BLACK; | 
|---|
| 481 | y->color = BLACK; | 
|---|
| 482 | x->parent->parent->color = RED; | 
|---|
| 483 | x = x->parent->parent; | 
|---|
| 484 | } | 
|---|
| 485 | else | 
|---|
| 486 | { | 
|---|
| 487 | // uncle is BLACK | 
|---|
| 488 | if (x == x->parent->left) | 
|---|
| 489 | { | 
|---|
| 490 | x = x->parent; | 
|---|
| 491 | rotateRight(root, | 
|---|
| 492 | x); | 
|---|
| 493 | } | 
|---|
| 494 | x->parent->color = BLACK; | 
|---|
| 495 | x->parent->parent->color = RED; | 
|---|
| 496 | rotateLeft(root, | 
|---|
| 497 | x->parent->parent); | 
|---|
| 498 | } | 
|---|
| 499 | } | 
|---|
| 500 | } | 
|---|
| 501 |  | 
|---|
| 502 | (*root)->color = BLACK; | 
|---|
| 503 | } | 
|---|
| 504 |  | 
|---|
| 505 | /* | 
|---|
| 506 | *@@ treeInsert: | 
|---|
| 507 | *      inserts a new tree node into the specified | 
|---|
| 508 | *      tree, using the specified comparison function | 
|---|
| 509 | *      for sorting. | 
|---|
| 510 | * | 
|---|
| 511 | *      "x" specifies the new tree node which must | 
|---|
| 512 | *      have been allocated by the caller. x->ulKey | 
|---|
| 513 | *      must already contain the node's key (data) | 
|---|
| 514 | *      which the sort function can understand. | 
|---|
| 515 | * | 
|---|
| 516 | *      This function will then set the parent, | 
|---|
| 517 | *      left, right, and color members. In addition, | 
|---|
| 518 | *      if (plCount != NULL), *plCount is raised by | 
|---|
| 519 | *      one. | 
|---|
| 520 | * | 
|---|
| 521 | *      Returns 0 if no error. Might return | 
|---|
| 522 | *      STATUS_DUPLICATE_KEY if a node with the | 
|---|
| 523 | *      same ulKey already exists. | 
|---|
| 524 | * | 
|---|
| 525 | *@@changed V0.9.16 (2001-10-19) [umoeller]: added plCount | 
|---|
| 526 | */ | 
|---|
| 527 |  | 
|---|
| 528 | int treeInsert(TREE **root,                     // in: root of the tree | 
|---|
| 529 | PLONG plCount,                   // in/out: item count (ptr can be NULL) | 
|---|
| 530 | TREE *x,                         // in: new node to insert | 
|---|
| 531 | FNTREE_COMPARE *pfnCompare)      // in: comparison func | 
|---|
| 532 | { | 
|---|
| 533 | TREE    *current, | 
|---|
| 534 | *parent; | 
|---|
| 535 |  | 
|---|
| 536 | unsigned long key = x->ulKey; | 
|---|
| 537 |  | 
|---|
| 538 | // find future parent | 
|---|
| 539 | current = *root; | 
|---|
| 540 | parent = 0; | 
|---|
| 541 |  | 
|---|
| 542 | while (current != LEAF) | 
|---|
| 543 | { | 
|---|
| 544 | int iResult; | 
|---|
| 545 | if (!(iResult = pfnCompare(key, current->ulKey))) | 
|---|
| 546 | return STATUS_DUPLICATE_KEY; | 
|---|
| 547 |  | 
|---|
| 548 | parent = current; | 
|---|
| 549 | current = (iResult < 0) | 
|---|
| 550 | ? current->left | 
|---|
| 551 | : current->right; | 
|---|
| 552 | } | 
|---|
| 553 |  | 
|---|
| 554 | // set up new node | 
|---|
| 555 | x->parent = parent; | 
|---|
| 556 | x->left = LEAF; | 
|---|
| 557 | x->right = LEAF; | 
|---|
| 558 | x->color = RED; | 
|---|
| 559 |  | 
|---|
| 560 | // insert node in tree | 
|---|
| 561 | if (parent) | 
|---|
| 562 | { | 
|---|
| 563 | if (pfnCompare(key, parent->ulKey) < 0) // (compLT(key, parent->key)) | 
|---|
| 564 | parent->left = x; | 
|---|
| 565 | else | 
|---|
| 566 | parent->right = x; | 
|---|
| 567 | } | 
|---|
| 568 | else | 
|---|
| 569 | *root = x; | 
|---|
| 570 |  | 
|---|
| 571 | insertFixup(root, | 
|---|
| 572 | x); | 
|---|
| 573 |  | 
|---|
| 574 | if (plCount) | 
|---|
| 575 | (*plCount)++;       // V0.9.16 (2001-10-19) [umoeller] | 
|---|
| 576 |  | 
|---|
| 577 | return STATUS_OK; | 
|---|
| 578 | } | 
|---|
| 579 |  | 
|---|
| 580 | /* | 
|---|
| 581 | *@@ deleteFixup: | 
|---|
| 582 | * | 
|---|
| 583 | */ | 
|---|
| 584 |  | 
|---|
| 585 | STATIC void deleteFixup(TREE **root, | 
|---|
| 586 | TREE *tree) | 
|---|
| 587 | { | 
|---|
| 588 | TREE    *s; | 
|---|
| 589 |  | 
|---|
| 590 | while (    tree != *root | 
|---|
| 591 | && tree->color == BLACK | 
|---|
| 592 | ) | 
|---|
| 593 | { | 
|---|
| 594 | if (tree == tree->parent->left) | 
|---|
| 595 | { | 
|---|
| 596 | s = tree->parent->right; | 
|---|
| 597 | if (s->color == RED) | 
|---|
| 598 | { | 
|---|
| 599 | s->color = BLACK; | 
|---|
| 600 | tree->parent->color = RED; | 
|---|
| 601 | rotateLeft(root, tree->parent); | 
|---|
| 602 | s = tree->parent->right; | 
|---|
| 603 | } | 
|---|
| 604 | if (    (s->left->color == BLACK) | 
|---|
| 605 | && (s->right->color == BLACK) | 
|---|
| 606 | ) | 
|---|
| 607 | { | 
|---|
| 608 | s->color = RED; | 
|---|
| 609 | tree = tree->parent; | 
|---|
| 610 | } | 
|---|
| 611 | else | 
|---|
| 612 | { | 
|---|
| 613 | if (s->right->color == BLACK) | 
|---|
| 614 | { | 
|---|
| 615 | s->left->color = BLACK; | 
|---|
| 616 | s->color = RED; | 
|---|
| 617 | rotateRight(root, s); | 
|---|
| 618 | s = tree->parent->right; | 
|---|
| 619 | } | 
|---|
| 620 | s->color = tree->parent->color; | 
|---|
| 621 | tree->parent->color = BLACK; | 
|---|
| 622 | s->right->color = BLACK; | 
|---|
| 623 | rotateLeft(root, tree->parent); | 
|---|
| 624 | tree = *root; | 
|---|
| 625 | } | 
|---|
| 626 | } | 
|---|
| 627 | else | 
|---|
| 628 | { | 
|---|
| 629 | s = tree->parent->left; | 
|---|
| 630 | if (s->color == RED) | 
|---|
| 631 | { | 
|---|
| 632 | s->color = BLACK; | 
|---|
| 633 | tree->parent->color = RED; | 
|---|
| 634 | rotateRight(root, tree->parent); | 
|---|
| 635 | s = tree->parent->left; | 
|---|
| 636 | } | 
|---|
| 637 | if (    (s->right->color == BLACK) | 
|---|
| 638 | && (s->left->color == BLACK) | 
|---|
| 639 | ) | 
|---|
| 640 | { | 
|---|
| 641 | s->color = RED; | 
|---|
| 642 | tree = tree->parent; | 
|---|
| 643 | } | 
|---|
| 644 | else | 
|---|
| 645 | { | 
|---|
| 646 | if (s->left->color == BLACK) | 
|---|
| 647 | { | 
|---|
| 648 | s->right->color = BLACK; | 
|---|
| 649 | s->color = RED; | 
|---|
| 650 | rotateLeft(root, s); | 
|---|
| 651 | s = tree->parent->left; | 
|---|
| 652 | } | 
|---|
| 653 | s->color = tree->parent->color; | 
|---|
| 654 | tree->parent->color = BLACK; | 
|---|
| 655 | s->left->color = BLACK; | 
|---|
| 656 | rotateRight (root, tree->parent); | 
|---|
| 657 | tree = *root; | 
|---|
| 658 | } | 
|---|
| 659 | } | 
|---|
| 660 | } | 
|---|
| 661 |  | 
|---|
| 662 | tree->color = BLACK; | 
|---|
| 663 | } | 
|---|
| 664 |  | 
|---|
| 665 | /* | 
|---|
| 666 | *@@ treeDelete: | 
|---|
| 667 | *      removes the specified node from the tree. | 
|---|
| 668 | *      Does not free() the node though. | 
|---|
| 669 | * | 
|---|
| 670 | *      In addition, if (plCount != NULL), *plCount is | 
|---|
| 671 | *      decremented. | 
|---|
| 672 | * | 
|---|
| 673 | *      Returns 0 if the node was deleted or | 
|---|
| 674 | *      STATUS_INVALID_NODE if not. | 
|---|
| 675 | * | 
|---|
| 676 | *@@changed V0.9.16 (2001-10-19) [umoeller]: added plCount | 
|---|
| 677 | */ | 
|---|
| 678 |  | 
|---|
| 679 | int treeDelete(TREE **root,         // in: root of the tree | 
|---|
| 680 | PLONG plCount,       // in/out: item count (ptr can be NULL) | 
|---|
| 681 | TREE *tree)          // in: tree node to delete | 
|---|
| 682 | { | 
|---|
| 683 | TREE        *y, | 
|---|
| 684 | *d; | 
|---|
| 685 | nodeColor   color; | 
|---|
| 686 |  | 
|---|
| 687 | if (    (!tree) | 
|---|
| 688 | || (tree == LEAF) | 
|---|
| 689 | ) | 
|---|
| 690 | return STATUS_INVALID_NODE; | 
|---|
| 691 |  | 
|---|
| 692 | if (    (tree->left  == LEAF) | 
|---|
| 693 | || (tree->right == LEAF) | 
|---|
| 694 | ) | 
|---|
| 695 | // d has a TREE_NULL node as a child | 
|---|
| 696 | d = tree; | 
|---|
| 697 | else | 
|---|
| 698 | { | 
|---|
| 699 | // find tree successor with a TREE_NULL node as a child | 
|---|
| 700 | d = tree->right; | 
|---|
| 701 | while (d->left != LEAF) | 
|---|
| 702 | d = d->left; | 
|---|
| 703 | } | 
|---|
| 704 |  | 
|---|
| 705 | // y is d's only child, if there is one, else TREE_NULL | 
|---|
| 706 | if (d->left != LEAF) | 
|---|
| 707 | y = d->left; | 
|---|
| 708 | else | 
|---|
| 709 | y = d->right; | 
|---|
| 710 |  | 
|---|
| 711 | // remove d from the parent chain | 
|---|
| 712 | if (y != LEAF) | 
|---|
| 713 | y->parent = d->parent; | 
|---|
| 714 |  | 
|---|
| 715 | if (d->parent) | 
|---|
| 716 | { | 
|---|
| 717 | if (d == d->parent->left) | 
|---|
| 718 | d->parent->left  = y; | 
|---|
| 719 | else | 
|---|
| 720 | d->parent->right = y; | 
|---|
| 721 | } | 
|---|
| 722 | else | 
|---|
| 723 | *root = y; | 
|---|
| 724 |  | 
|---|
| 725 | color = d->color; | 
|---|
| 726 |  | 
|---|
| 727 | if (d != tree) | 
|---|
| 728 | { | 
|---|
| 729 | // move the data from d to tree; we do this by | 
|---|
| 730 | // linking d into the structure in the place of tree | 
|---|
| 731 | d->left   = tree->left; | 
|---|
| 732 | d->right  = tree->right; | 
|---|
| 733 | d->parent = tree->parent; | 
|---|
| 734 | d->color  = tree->color; | 
|---|
| 735 |  | 
|---|
| 736 | if (d->parent) | 
|---|
| 737 | { | 
|---|
| 738 | if (tree == d->parent->left) | 
|---|
| 739 | d->parent->left  = d; | 
|---|
| 740 | else | 
|---|
| 741 | d->parent->right = d; | 
|---|
| 742 | } | 
|---|
| 743 | else | 
|---|
| 744 | *root = d; | 
|---|
| 745 |  | 
|---|
| 746 | if (d->left != LEAF) | 
|---|
| 747 | d->left->parent = d; | 
|---|
| 748 |  | 
|---|
| 749 | if (d->right != LEAF) | 
|---|
| 750 | d->right->parent = d; | 
|---|
| 751 | } | 
|---|
| 752 |  | 
|---|
| 753 | if (    (y != LEAF) | 
|---|
| 754 | && (color == BLACK) | 
|---|
| 755 | ) | 
|---|
| 756 | deleteFixup(root, | 
|---|
| 757 | y); | 
|---|
| 758 |  | 
|---|
| 759 | if (plCount) | 
|---|
| 760 | (*plCount)--;       // V0.9.16 (2001-10-19) [umoeller] | 
|---|
| 761 |  | 
|---|
| 762 | return (STATUS_OK); | 
|---|
| 763 | } | 
|---|
| 764 |  | 
|---|
| 765 | /* | 
|---|
| 766 | *@@ treeFind: | 
|---|
| 767 | *      finds the tree node with the specified key. | 
|---|
| 768 | *      Returns NULL if none exists. | 
|---|
| 769 | */ | 
|---|
| 770 |  | 
|---|
| 771 | TREE* treeFind(TREE *root,                    // in: root of the tree | 
|---|
| 772 | unsigned long key,             // in: key to find | 
|---|
| 773 | FNTREE_COMPARE *pfnCompare)    // in: comparison func | 
|---|
| 774 | { | 
|---|
| 775 | TREE *current = root; | 
|---|
| 776 | while (current != LEAF) | 
|---|
| 777 | { | 
|---|
| 778 | int iResult; | 
|---|
| 779 | if (!(iResult = pfnCompare(key, current->ulKey))) | 
|---|
| 780 | return current; | 
|---|
| 781 |  | 
|---|
| 782 | current = (iResult < 0) | 
|---|
| 783 | ? current->left | 
|---|
| 784 | : current->right; | 
|---|
| 785 | } | 
|---|
| 786 |  | 
|---|
| 787 | return 0; | 
|---|
| 788 | } | 
|---|
| 789 |  | 
|---|
| 790 | /* | 
|---|
| 791 | *@@ treeFirst: | 
|---|
| 792 | *      finds and returns the first node in a (sub-)tree. | 
|---|
| 793 | * | 
|---|
| 794 | *      See treeNext for a sample usage for traversing a tree. | 
|---|
| 795 | */ | 
|---|
| 796 |  | 
|---|
| 797 | TREE* treeFirst(TREE *r) | 
|---|
| 798 | { | 
|---|
| 799 | TREE    *p; | 
|---|
| 800 |  | 
|---|
| 801 | if (    (!r) | 
|---|
| 802 | || (r == LEAF) | 
|---|
| 803 | ) | 
|---|
| 804 | return NULL; | 
|---|
| 805 |  | 
|---|
| 806 | p = r; | 
|---|
| 807 | while (p->left != LEAF) | 
|---|
| 808 | p = p->left; | 
|---|
| 809 |  | 
|---|
| 810 | return p; | 
|---|
| 811 | } | 
|---|
| 812 |  | 
|---|
| 813 | /* | 
|---|
| 814 | *@@ treeLast: | 
|---|
| 815 | *      finds and returns the last node in a (sub-)tree. | 
|---|
| 816 | */ | 
|---|
| 817 |  | 
|---|
| 818 | TREE* treeLast(TREE *r) | 
|---|
| 819 | { | 
|---|
| 820 | TREE    *p; | 
|---|
| 821 |  | 
|---|
| 822 | if (    (!r) | 
|---|
| 823 | || (r == LEAF)) | 
|---|
| 824 | return NULL; | 
|---|
| 825 |  | 
|---|
| 826 | p = r; | 
|---|
| 827 | while (p->right != LEAF) | 
|---|
| 828 | p = p->right; | 
|---|
| 829 |  | 
|---|
| 830 | return p; | 
|---|
| 831 | } | 
|---|
| 832 |  | 
|---|
| 833 | /* | 
|---|
| 834 | *@@ treeNext: | 
|---|
| 835 | *      finds and returns the next node in a tree. | 
|---|
| 836 | * | 
|---|
| 837 | *      Example for traversing a whole tree: | 
|---|
| 838 | * | 
|---|
| 839 | +          TREE    *TreeRoot; | 
|---|
| 840 | +          ... | 
|---|
| 841 | +          TREE* pNode = treeFirst(TreeRoot); | 
|---|
| 842 | +          while (pNode) | 
|---|
| 843 | +          { | 
|---|
| 844 | +              ... | 
|---|
| 845 | +              pNode = treeNext(pNode); | 
|---|
| 846 | +          } | 
|---|
| 847 | * | 
|---|
| 848 | *      This runs through the tree items in sorted order. | 
|---|
| 849 | */ | 
|---|
| 850 |  | 
|---|
| 851 | TREE* treeNext(TREE *r) | 
|---|
| 852 | { | 
|---|
| 853 | TREE    *p, | 
|---|
| 854 | *child; | 
|---|
| 855 |  | 
|---|
| 856 | if (    (!r) | 
|---|
| 857 | || (r == LEAF) | 
|---|
| 858 | ) | 
|---|
| 859 | return NULL; | 
|---|
| 860 |  | 
|---|
| 861 | p = r; | 
|---|
| 862 | if (p->right != LEAF) | 
|---|
| 863 | return treeFirst(p->right); | 
|---|
| 864 |  | 
|---|
| 865 | p = r; | 
|---|
| 866 | child   = LEAF; | 
|---|
| 867 | while (    (p->parent) | 
|---|
| 868 | && (p->right == child) | 
|---|
| 869 | ) | 
|---|
| 870 | { | 
|---|
| 871 | child = p; | 
|---|
| 872 | p = p->parent; | 
|---|
| 873 | } | 
|---|
| 874 |  | 
|---|
| 875 | if (p->right != child) | 
|---|
| 876 | return p; | 
|---|
| 877 |  | 
|---|
| 878 | return NULL; | 
|---|
| 879 | } | 
|---|
| 880 |  | 
|---|
| 881 | /* | 
|---|
| 882 | *@@ treePrev: | 
|---|
| 883 | *      finds and returns the previous node in a tree. | 
|---|
| 884 | */ | 
|---|
| 885 |  | 
|---|
| 886 | TREE* treePrev(TREE *r) | 
|---|
| 887 | { | 
|---|
| 888 | TREE    *p, | 
|---|
| 889 | *child; | 
|---|
| 890 |  | 
|---|
| 891 | if (    (!r) | 
|---|
| 892 | || (r == LEAF) | 
|---|
| 893 | ) | 
|---|
| 894 | return NULL; | 
|---|
| 895 |  | 
|---|
| 896 | p = r; | 
|---|
| 897 | if (p->left != LEAF) | 
|---|
| 898 | return treeLast (p->left); | 
|---|
| 899 |  | 
|---|
| 900 | p = r; | 
|---|
| 901 | child   = LEAF; | 
|---|
| 902 | while (    (p->parent) | 
|---|
| 903 | && (p->left == child) | 
|---|
| 904 | ) | 
|---|
| 905 | { | 
|---|
| 906 | child = p; | 
|---|
| 907 | p = p->parent; | 
|---|
| 908 | } | 
|---|
| 909 |  | 
|---|
| 910 | if (p->left != child) | 
|---|
| 911 | return p; | 
|---|
| 912 |  | 
|---|
| 913 | return NULL; | 
|---|
| 914 | } | 
|---|
| 915 |  | 
|---|
| 916 | /* | 
|---|
| 917 | *@@ treeBuildArray: | 
|---|
| 918 | *      builds an array of TREE* pointers containing | 
|---|
| 919 | *      all tree items in sorted order. | 
|---|
| 920 | * | 
|---|
| 921 | *      This returns a TREE** pointer to the array. | 
|---|
| 922 | *      Each item in the array is a TREE* pointer to | 
|---|
| 923 | *      the respective tree item. | 
|---|
| 924 | * | 
|---|
| 925 | *      The array has been allocated using malloc() | 
|---|
| 926 | *      and must be free()'d by the caller. | 
|---|
| 927 | * | 
|---|
| 928 | *      NOTE: This will only work if you maintain a | 
|---|
| 929 | *      tree node count yourself, which you must pass | 
|---|
| 930 | *      in *pulCount on input. | 
|---|
| 931 | * | 
|---|
| 932 | *      This is most useful if you want to delete an | 
|---|
| 933 | *      entire tree without having to traverse it | 
|---|
| 934 | *      and rebalance the tree on every delete. | 
|---|
| 935 | * | 
|---|
| 936 | *      Example usage for deletion: | 
|---|
| 937 | * | 
|---|
| 938 | +          TREE    *G_TreeRoot; | 
|---|
| 939 | +          treeInit(&G_TreeRoot); | 
|---|
| 940 | + | 
|---|
| 941 | +          // add stuff to the tree | 
|---|
| 942 | +          TREE    *pNewNode = malloc(...); | 
|---|
| 943 | +          treeInsert(&G_TreeRoot, pNewNode, fnCompare) | 
|---|
| 944 | + | 
|---|
| 945 | +          // now delete all nodes | 
|---|
| 946 | +          ULONG   cItems = ... // insert item count here | 
|---|
| 947 | +          TREE**  papNodes = treeBuildArray(G_TreeRoot, | 
|---|
| 948 | +                                            &cItems); | 
|---|
| 949 | +          if (papNodes) | 
|---|
| 950 | +          { | 
|---|
| 951 | +              ULONG ul; | 
|---|
| 952 | +              for (ul = 0; ul < cItems; ul++) | 
|---|
| 953 | +              { | 
|---|
| 954 | +                  TREE *pNodeThis = papNodes[ul]; | 
|---|
| 955 | +                  free(pNodeThis); | 
|---|
| 956 | +              } | 
|---|
| 957 | + | 
|---|
| 958 | +              free(papNodes); | 
|---|
| 959 | +          } | 
|---|
| 960 | + | 
|---|
| 961 | * | 
|---|
| 962 | *@@added V0.9.9 (2001-04-05) [umoeller] | 
|---|
| 963 | */ | 
|---|
| 964 |  | 
|---|
| 965 | TREE** treeBuildArray(TREE* pRoot, | 
|---|
| 966 | PLONG plCount)  // in: item count, out: array item count | 
|---|
| 967 | { | 
|---|
| 968 | TREE            **papNodes = NULL, | 
|---|
| 969 | **papThis = NULL; | 
|---|
| 970 | long            cb = (sizeof(TREE*) * (*plCount)), | 
|---|
| 971 | cNodes = 0; | 
|---|
| 972 |  | 
|---|
| 973 | if (cb) | 
|---|
| 974 | { | 
|---|
| 975 | papNodes = (TREE**)malloc(cb); | 
|---|
| 976 | papThis = papNodes; | 
|---|
| 977 |  | 
|---|
| 978 | if (papNodes) | 
|---|
| 979 | { | 
|---|
| 980 | TREE    *pNode = (TREE*)treeFirst(pRoot); | 
|---|
| 981 |  | 
|---|
| 982 | memset(papNodes, 0, cb); | 
|---|
| 983 |  | 
|---|
| 984 | // copy nodes to array | 
|---|
| 985 | while (    pNode | 
|---|
| 986 | && cNodes < (*plCount)     // just to make sure | 
|---|
| 987 | ) | 
|---|
| 988 | { | 
|---|
| 989 | *papThis = pNode; | 
|---|
| 990 | cNodes++; | 
|---|
| 991 | papThis++; | 
|---|
| 992 |  | 
|---|
| 993 | pNode = (TREE*)treeNext(pNode); | 
|---|
| 994 | } | 
|---|
| 995 |  | 
|---|
| 996 | // output count | 
|---|
| 997 | *plCount = cNodes; | 
|---|
| 998 | } | 
|---|
| 999 | } | 
|---|
| 1000 |  | 
|---|
| 1001 | return (papNodes); | 
|---|
| 1002 | } | 
|---|
| 1003 |  | 
|---|
| 1004 | /* void main(int argc, char **argv) { | 
|---|
| 1005 | int maxnum, ct; | 
|---|
| 1006 | recType rec; | 
|---|
| 1007 | keyType key; | 
|---|
| 1008 | statusEnum status; | 
|---|
| 1009 |  | 
|---|
| 1010 | maxnum = atoi(argv[1]); | 
|---|
| 1011 |  | 
|---|
| 1012 | printf("maxnum = %d\n", maxnum); | 
|---|
| 1013 | for (ct = maxnum; ct; ct--) { | 
|---|
| 1014 | key = rand() % 9 + 1; | 
|---|
| 1015 | if ((status = find(key, &rec)) == STATUS_OK) { | 
|---|
| 1016 | status = delete(key); | 
|---|
| 1017 | if (status) printf("fail: status = %d\n", status); | 
|---|
| 1018 | } else { | 
|---|
| 1019 | status = insert(key, &rec); | 
|---|
| 1020 | if (status) printf("fail: status = %d\n", status); | 
|---|
| 1021 | } | 
|---|
| 1022 | } | 
|---|
| 1023 | } */ | 
|---|