source: trunk/src/helpers/tree.c@ 106

Last change on this file since 106 was 106, checked in by umoeller, 24 years ago

Misc helpers updates.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 33.1 KB
Line 
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 M”ller.
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
271static TREE sentinel = { LEAF, LEAF, 0, BLACK};
272
273/*
274A binary search tree is a red-black tree if:
275
2761. Every node is either red or black.
2772. Every leaf (nil) is black.
2783. If a node is red, then both its children are black.
2794. 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 */
288
289void treeInit(TREE **root)
290{
291 *root = LEAF;
292}
293
294/*
295 *@@ treeCompareKeys:
296 * standard comparison func if the TREE.ulKey
297 * field really is a ULONG.
298 */
299
300int TREEENTRY treeCompareKeys(unsigned long ul1, unsigned long ul2)
301{
302 if (ul1 < ul2)
303 return -1;
304 if (ul1 > ul2)
305 return +1;
306 return (0);
307}
308
309/*
310 *@@ treeCompareStrings:
311 * standard comparison func if the TREE.ulKey
312 * field really is a string pointer (PCSZ).
313 *
314 * This runs strcmp internally, but can handle
315 * NULL pointers without crashing.
316 *
317 *@@added V0.9.16 (2001-09-29) [umoeller]
318 */
319
320int TREEENTRY treeCompareStrings(unsigned long ul1, unsigned long ul2)
321{
322 #define p1 (const char*)(ul1)
323 #define p2 (const char*)(ul2)
324
325 if (p1 && p2)
326 {
327 int i = strcmp(p1, p2);
328 if (i < 0) return (-1);
329 if (i > 0) return (+1);
330 }
331 else if (p1)
332 // but p2 is NULL: p1 greater than p2 then
333 return (+1);
334 else if (p2)
335 // but p1 is NULL: p1 less than p2 then
336 return (-1);
337
338 // return 0 if strcmp returned 0 above or both strings are NULL
339 return (0);
340}
341
342/*
343 *@@ rotateLeft:
344 * private function during rebalancing.
345 */
346
347static void rotateLeft(TREE **root,
348 TREE *x)
349{
350 /**************************
351 * rotate node x to left *
352 **************************/
353
354 TREE *y = x->right;
355
356 // establish x->right link
357 x->right = y->left;
358 if (y->left != LEAF)
359 y->left->parent = x;
360
361 // establish y->parent link
362 if (y != LEAF)
363 y->parent = x->parent;
364 if (x->parent)
365 {
366 if (x == x->parent->left)
367 x->parent->left = y;
368 else
369 x->parent->right = y;
370 }
371 else
372 *root = y;
373
374 // link x and y
375 y->left = x;
376 if (x != LEAF)
377 x->parent = y;
378}
379
380/*
381 *@@ rotateRight:
382 * private function during rebalancing.
383 */
384
385static void rotateRight(TREE **root,
386 TREE *x)
387{
388
389 /****************************
390 * rotate node x to right *
391 ****************************/
392
393 TREE *y = x->left;
394
395 // establish x->left link
396 x->left = y->right;
397 if (y->right != LEAF)
398 y->right->parent = x;
399
400 // establish y->parent link
401 if (y != LEAF)
402 y->parent = x->parent;
403 if (x->parent)
404 {
405 if (x == x->parent->right)
406 x->parent->right = y;
407 else
408 x->parent->left = y;
409 }
410 else
411 *root = y;
412
413 // link x and y
414 y->right = x;
415 if (x != LEAF)
416 x->parent = y;
417}
418
419/*
420 *@@ insertFixup:
421 * private function during rebalancing.
422 */
423
424static void insertFixup(TREE **root,
425 TREE *x)
426{
427 /*************************************
428 * maintain Red-Black tree balance *
429 * after inserting node x *
430 *************************************/
431
432 // check Red-Black properties
433 while ( x != *root
434 && x->parent->color == RED
435 )
436 {
437 // we have a violation
438 if (x->parent == x->parent->parent->left)
439 {
440 TREE *y = x->parent->parent->right;
441 if (y->color == RED)
442 {
443 // uncle is RED
444 x->parent->color = BLACK;
445 y->color = BLACK;
446 x->parent->parent->color = RED;
447 x = x->parent->parent;
448 }
449 else
450 {
451 // uncle is BLACK
452 if (x == x->parent->right)
453 {
454 // make x a left child
455 x = x->parent;
456 rotateLeft(root,
457 x);
458 }
459
460 // recolor and rotate
461 x->parent->color = BLACK;
462 x->parent->parent->color = RED;
463 rotateRight(root,
464 x->parent->parent);
465 }
466 }
467 else
468 {
469 // mirror image of above code
470 TREE *y = x->parent->parent->left;
471 if (y->color == RED)
472 {
473 // uncle is RED
474 x->parent->color = BLACK;
475 y->color = BLACK;
476 x->parent->parent->color = RED;
477 x = x->parent->parent;
478 }
479 else
480 {
481 // uncle is BLACK
482 if (x == x->parent->left)
483 {
484 x = x->parent;
485 rotateRight(root,
486 x);
487 }
488 x->parent->color = BLACK;
489 x->parent->parent->color = RED;
490 rotateLeft(root,
491 x->parent->parent);
492 }
493 }
494 }
495 (*root)->color = BLACK;
496}
497
498/*
499 *@@ treeInsert:
500 * inserts a new tree node into the specified
501 * tree, using the specified comparison function
502 * for sorting.
503 *
504 * "x" specifies the new tree node which must
505 * have been allocated by the caller. x->ulKey
506 * must already contain the node's key (data).
507 * This function will then set the parent,
508 * left, right, and color members.
509 *
510 * Returns 0 if no error. Might return
511 * STATUS_DUPLICATE_KEY if a node with the
512 * same ulKey already exists.
513 */
514
515int treeInsert(TREE **root, // in: root of the tree
516 TREE *x, // in: new node to insert
517 FNTREE_COMPARE *pfnCompare) // in: comparison func
518{
519 TREE *current,
520 *parent;
521
522 unsigned long key = x->ulKey;
523
524 // find future parent
525 current = *root;
526 parent = 0;
527
528 while (current != LEAF)
529 {
530 int iResult;
531 if (0 == (iResult = pfnCompare(key, current->ulKey))) // if (compEQ(key, current->key))
532 return STATUS_DUPLICATE_KEY;
533 parent = current;
534 current = (iResult < 0) // compLT(key, current->key)
535 ? current->left
536 : current->right;
537 }
538
539 // set up new node
540 /* if ((x = malloc (sizeof(*x))) == 0)
541 return STATUS_MEM_EXHAUSTED; */
542 x->parent = parent;
543 x->left = LEAF;
544 x->right = LEAF;
545 x->color = RED;
546 // x->key = key;
547 // x->rec = *rec;
548
549 // insert node in tree
550 if (parent)
551 {
552 if (pfnCompare(key, parent->ulKey) < 0) // (compLT(key, parent->key))
553 parent->left = x;
554 else
555 parent->right = x;
556 }
557 else
558 *root = x;
559
560 insertFixup(root,
561 x);
562 // lastFind = NULL;
563
564 return STATUS_OK;
565}
566
567/*
568 *@@ deleteFixup:
569 *
570 */
571
572static void deleteFixup(TREE **root,
573 TREE *tree)
574{
575 TREE *s;
576
577 while ( tree != *root
578 && tree->color == BLACK
579 )
580 {
581 if (tree == tree->parent->left)
582 {
583 s = tree->parent->right;
584 if (s->color == RED)
585 {
586 s->color = BLACK;
587 tree->parent->color = RED;
588 rotateLeft(root, tree->parent);
589 s = tree->parent->right;
590 }
591 if ( (s->left->color == BLACK)
592 && (s->right->color == BLACK)
593 )
594 {
595 s->color = RED;
596 tree = tree->parent;
597 }
598 else
599 {
600 if (s->right->color == BLACK)
601 {
602 s->left->color = BLACK;
603 s->color = RED;
604 rotateRight(root, s);
605 s = tree->parent->right;
606 }
607 s->color = tree->parent->color;
608 tree->parent->color = BLACK;
609 s->right->color = BLACK;
610 rotateLeft(root, tree->parent);
611 tree = *root;
612 }
613 }
614 else
615 {
616 s = tree->parent->left;
617 if (s->color == RED)
618 {
619 s->color = BLACK;
620 tree->parent->color = RED;
621 rotateRight(root, tree->parent);
622 s = tree->parent->left;
623 }
624 if ( (s->right->color == BLACK)
625 && (s->left->color == BLACK)
626 )
627 {
628 s->color = RED;
629 tree = tree->parent;
630 }
631 else
632 {
633 if (s->left->color == BLACK)
634 {
635 s->right->color = BLACK;
636 s->color = RED;
637 rotateLeft(root, s);
638 s = tree->parent->left;
639 }
640 s->color = tree->parent->color;
641 tree->parent->color = BLACK;
642 s->left->color = BLACK;
643 rotateRight (root, tree->parent);
644 tree = *root;
645 }
646 }
647 }
648 tree->color = BLACK;
649
650 /*************************************
651 * maintain Red-Black tree balance *
652 * after deleting node x *
653 *************************************/
654
655 /* while ( x != *root
656 && x->color == BLACK
657 )
658 {
659 if (x == x->parent->left)
660 {
661 TREE *w = x->parent->right;
662 if (w->color == RED)
663 {
664 w->color = BLACK;
665 x->parent->color = RED;
666 rotateLeft(root,
667 x->parent);
668 w = x->parent->right;
669 }
670 if ( w->left->color == BLACK
671 && w->right->color == BLACK
672 )
673 {
674 w->color = RED;
675 x = x->parent;
676 }
677 else
678 {
679 if (w->right->color == BLACK)
680 {
681 w->left->color = BLACK;
682 w->color = RED;
683 rotateRight(root,
684 w);
685 w = x->parent->right;
686 }
687 w->color = x->parent->color;
688 x->parent->color = BLACK;
689 w->right->color = BLACK;
690 rotateLeft(root,
691 x->parent);
692 x = *root;
693 }
694 }
695 else
696 {
697 TREE *w = x->parent->left;
698 if (w->color == RED)
699 {
700 w->color = BLACK;
701 x->parent->color = RED;
702 rotateRight(root,
703 x->parent);
704 w = x->parent->left;
705 }
706 if ( w->right->color == BLACK
707 && w->left->color == BLACK
708 )
709 {
710 w->color = RED;
711 x = x->parent;
712 }
713 else
714 {
715 if (w->left->color == BLACK)
716 {
717 w->right->color = BLACK;
718 w->color = RED;
719 rotateLeft(root,
720 w);
721 w = x->parent->left;
722 }
723 w->color = x->parent->color;
724 x->parent->color = BLACK;
725 w->left->color = BLACK;
726 rotateRight(root,
727 x->parent);
728 x = *root;
729 }
730 }
731 }
732 x->color = BLACK; */
733}
734
735/*
736 *@@ treeDelete:
737 * removes the specified node from the tree.
738 * Does not free() the node though.
739 *
740 * Returns 0 if the node was deleted or
741 * STATUS_INVALID_NODE if not.
742 */
743
744int treeDelete(TREE **root, // in: root of the tree
745 TREE *tree) // in: tree node to delete
746{
747 TREE *y,
748 *d;
749 nodeColor color;
750
751 if ( (!tree)
752 || (tree == LEAF)
753 )
754 return STATUS_INVALID_NODE;
755
756 if ( (tree->left == LEAF)
757 || (tree->right == LEAF)
758 )
759 // d has a TREE_NULL node as a child
760 d = tree;
761 else
762 {
763 // find tree successor with a TREE_NULL node as a child
764 d = tree->right;
765 while (d->left != LEAF)
766 d = d->left;
767 }
768
769 // y is d's only child, if there is one, else TREE_NULL
770 if (d->left != LEAF)
771 y = d->left;
772 else
773 y = d->right;
774
775 // remove d from the parent chain
776 if (y != LEAF)
777 y->parent = d->parent;
778 if (d->parent)
779 {
780 if (d == d->parent->left)
781 d->parent->left = y;
782 else
783 d->parent->right = y;
784 }
785 else
786 *root = y;
787
788 color = d->color;
789
790 if (d != tree)
791 {
792 // move the data from d to tree; we do this by
793 // linking d into the structure in the place of tree
794 d->left = tree->left;
795 d->right = tree->right;
796 d->parent = tree->parent;
797 d->color = tree->color;
798
799 if (d->parent)
800 {
801 if (tree == d->parent->left)
802 d->parent->left = d;
803 else
804 d->parent->right = d;
805 }
806 else
807 *root = d;
808
809 if (d->left != LEAF)
810 d->left->parent = d;
811
812 if (d->right != LEAF)
813 d->right->parent = d;
814 }
815
816 if ( (y != LEAF)
817 && (color == BLACK)
818 )
819 deleteFixup(root,
820 y);
821
822 return (STATUS_OK);
823
824 /* TREE *x,
825 *y; */
826 // *z;
827
828 /*****************************
829 * delete node z from tree *
830 *****************************/
831
832 // find node in tree
833 /* if (lastFind && compEQ(lastFind->key, key))
834 // if we just found node, use pointer
835 z = lastFind;
836 else {
837 z = *root;
838 while(z != LEAF)
839 {
840 int iResult = pfnCompare(key, z->key);
841 if (iResult == 0)
842 // if(compEQ(key, z->key))
843 break;
844 else
845 z = (iResult < 0) // compLT(key, z->key)
846 ? z->left
847 : z->right;
848 }
849 if (z == LEAF)
850 return STATUS_KEY_NOT_FOUND;
851 }
852
853 if ( z->left == LEAF
854 || z->right == LEAF
855 )
856 {
857 // y has a LEAF node as a child
858 y = z;
859 }
860 else
861 {
862 // find tree successor with a LEAF node as a child
863 y = z->right;
864 while (y->left != LEAF)
865 y = y->left;
866 }
867
868 // x is y's only child
869 if (y->left != LEAF)
870 x = y->left;
871 else
872 x = y->right;
873
874 // remove y from the parent chain
875 x->parent = y->parent;
876 if (y->parent)
877 if (y == y->parent->left)
878 y->parent->left = x;
879 else
880 y->parent->right = x;
881 else
882 *root = x;
883
884 // y is about to be deleted...
885
886 if (y != z)
887 {
888 // now, the original code simply copied the data
889 // from y to z... we can't safely do that since
890 // we don't know about the real data in the
891 // caller's TREE structure
892 z->ulKey = y->ulKey;
893 // z->rec = y->rec; // hope this works...
894 // the original implementation used rec
895 // for the node's data
896
897 if (cbStruct > sizeof(TREE))
898 {
899 memcpy(((char*)&z) + sizeof(TREE),
900 ((char*)&y) + sizeof(TREE),
901 cbStruct - sizeof(TREE));
902 }
903 }
904
905 if (y->color == BLACK)
906 deleteFixup(root,
907 x);
908
909 // free(y);
910 // lastFind = NULL;
911
912 return STATUS_OK; */
913}
914
915/*
916 *@@ treeFind:
917 * finds the tree node with the specified key.
918 * Returns NULL if none exists.
919 */
920
921TREE* treeFind(TREE *root, // in: root of the tree
922 unsigned long key, // in: key to find
923 FNTREE_COMPARE *pfnCompare) // in: comparison func
924{
925 /*******************************
926 * find node containing data *
927 *******************************/
928
929 TREE *current = root;
930 while (current != LEAF)
931 {
932 int iResult;
933 if (0 == (iResult = pfnCompare(key, current->ulKey)))
934 return (current);
935 else
936 {
937 current = (iResult < 0) // compLT (key, current->key)
938 ? current->left
939 : current->right;
940 }
941 }
942
943 return 0;
944}
945
946/*
947 *@@ treeFirst:
948 * finds and returns the first node in a (sub-)tree.
949 *
950 * See treeNext for a sample usage for traversing a tree.
951 */
952
953TREE* treeFirst(TREE *r)
954{
955 TREE *p;
956
957 if ( (!r)
958 || (r == LEAF)
959 )
960 return NULL;
961
962 p = r;
963 while (p->left != LEAF)
964 p = p->left;
965
966 return p;
967}
968
969/*
970 *@@ treeLast:
971 * finds and returns the last node in a (sub-)tree.
972 */
973
974TREE* treeLast(TREE *r)
975{
976 TREE *p;
977
978 if ( (!r)
979 || (r == LEAF))
980 return NULL;
981
982 p = r;
983 while (p->right != LEAF)
984 p = p->right;
985
986 return p;
987}
988
989/*
990 *@@ treeNext:
991 * finds and returns the next node in a tree.
992 *
993 * Example for traversing a whole tree:
994 *
995 + TREE *TreeRoot;
996 + ...
997 + TREE* pNode = treeFirst(TreeRoot);
998 + while (pNode)
999 + {
1000 + ...
1001 + pNode = treeNext(pNode);
1002 + }
1003 *
1004 * This runs through the tree items in sorted order.
1005 */
1006
1007TREE* treeNext(TREE *r)
1008{
1009 TREE *p,
1010 *child;
1011
1012 if ( (!r)
1013 || (r == LEAF)
1014 )
1015 return NULL;
1016
1017 p = r;
1018 if (p->right != LEAF)
1019 return treeFirst (p->right);
1020 else
1021 {
1022 p = r;
1023 child = LEAF;
1024 while ( (p->parent)
1025 && (p->right == child)
1026 )
1027 {
1028 child = p;
1029 p = p->parent;
1030 }
1031 if (p->right != child)
1032 return p;
1033 else
1034 return NULL;
1035 }
1036}
1037
1038/*
1039 *@@ treePrev:
1040 * finds and returns the previous node in a tree.
1041 */
1042
1043TREE* treePrev(TREE *r)
1044{
1045 TREE *p,
1046 *child;
1047
1048 if ( (!r)
1049 || (r == LEAF))
1050 return NULL;
1051
1052 p = r;
1053 if (p->left != LEAF)
1054 return treeLast (p->left);
1055 else
1056 {
1057 p = r;
1058 child = LEAF;
1059 while ((p->parent)
1060 && (p->left == child))
1061 {
1062 child = p;
1063 p = p->parent;
1064 }
1065 if (p->left != child)
1066 return p;
1067 else
1068 return NULL;
1069 }
1070}
1071
1072/*
1073 *@@ treeBuildArray:
1074 * builds an array of TREE* pointers containing
1075 * all tree items in sorted order.
1076 *
1077 * This returns a TREE** pointer to the array.
1078 * Each item in the array is a TREE* pointer to
1079 * the respective tree item.
1080 *
1081 * The array has been allocated using malloc()
1082 * and must be free()'d by the caller.
1083 *
1084 * NOTE: This will only work if you maintain a
1085 * tree node count yourself, which you must pass
1086 * in *pulCount on input.
1087 *
1088 * This is most useful if you want to delete an
1089 * entire tree without having to traverse it
1090 * and rebalance the tree on every delete.
1091 *
1092 * Example usage for deletion:
1093 *
1094 + TREE *G_TreeRoot;
1095 + treeInit(&G_TreeRoot);
1096 +
1097 + // add stuff to the tree
1098 + TREE *pNewNode = malloc(...);
1099 + treeInsert(&G_TreeRoot, pNewNode, fnCompare)
1100 +
1101 + // now delete all nodes
1102 + ULONG cItems = ... // insert item count here
1103 + TREE** papNodes = treeBuildArray(G_TreeRoot,
1104 + &cItems);
1105 + if (papNodes)
1106 + {
1107 + ULONG ul;
1108 + for (ul = 0; ul < cItems; ul++)
1109 + {
1110 + TREE *pNodeThis = papNodes[ul];
1111 + free(pNodeThis);
1112 + }
1113 +
1114 + free(papNodes);
1115 + }
1116 +
1117 *
1118 *@@added V0.9.9 (2001-04-05) [umoeller]
1119 */
1120
1121TREE** treeBuildArray(TREE* pRoot,
1122 unsigned long *pulCount) // in: item count, out: array item count
1123{
1124 TREE **papNodes = NULL,
1125 **papThis = NULL;
1126 unsigned long cb = (sizeof(TREE*) * (*pulCount)),
1127 cNodes = 0;
1128
1129 if (cb)
1130 {
1131 papNodes = (TREE**)malloc(cb);
1132 papThis = papNodes;
1133
1134 if (papNodes)
1135 {
1136 TREE *pNode = (TREE*)treeFirst(pRoot);
1137
1138 memset(papNodes, 0, cb);
1139
1140 // copy nodes to array
1141 while ( pNode
1142 && cNodes < (*pulCount) // just to make sure
1143 )
1144 {
1145 *papThis = pNode;
1146 cNodes++;
1147 papThis++;
1148
1149 pNode = (TREE*)treeNext(pNode);
1150 }
1151
1152 // output count
1153 *pulCount = cNodes;
1154 }
1155 }
1156
1157 return (papNodes);
1158}
1159
1160/* void main(int argc, char **argv) {
1161 int maxnum, ct;
1162 recType rec;
1163 keyType key;
1164 statusEnum status;
1165
1166 maxnum = atoi(argv[1]);
1167
1168 printf("maxnum = %d\n", maxnum);
1169 for (ct = maxnum; ct; ct--) {
1170 key = rand() % 9 + 1;
1171 if ((status = find(key, &rec)) == STATUS_OK) {
1172 status = delete(key);
1173 if (status) printf("fail: status = %d\n", status);
1174 } else {
1175 status = insert(key, &rec);
1176 if (status) printf("fail: status = %d\n", status);
1177 }
1178 }
1179} */
Note: See TracBrowser for help on using the repository browser.