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

Last change on this file since 38 was 38, checked in by umoeller, 25 years ago

Updates to XML.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 30.3 KB
Line 
1
2/*
3 *@@sourcefile tree.c:
4 * contains helper functions for maintaining 'Red-Black' balanced
5 * binary trees.
6 * See explanations below.
7 *
8 * This file is all new with V0.9.5 (2000-09-29) [umoeller].
9 *
10 * Usage: All C programs; not OS/2-specific.
11 *
12 * Function prefixes (new with V0.81):
13 * -- tree* tree helper functions
14 *
15 * This has been taken from the Standard Function Library (SFL)
16 * by iMatix Corporation and changed to user the "id" member for
17 * tree sorting/comparison. This implementation is released
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.
62 *
63 * <B>Using binary trees</B>
64 *
65 * You can use any structure as elements in a tree, provided
66 * that the first member in the structure is a TREE structure
67 * (i.e. it has the left, right, parent, id, and colour members).
68 * The tree functions don't care what follows.
69 *
70 * So the implementation here is slightly different from the
71 * linked lists in linklist.c, because the LISTNODE structs
72 * only have pointers to the data. By contrast, the TREE structs
73 * are expected to contain the data themselves. See treeInsertID()
74 * for a sample.
75 *
76 * Initialize the root of the tree with treeInit(). Then
77 * add nodes to the tree with treeInsertID() and remove nodes
78 * with treeDelete().
79 *
80 * You can test whether a tree is empty by comparing its
81 * root with TREE_NULL.
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 *
108 * Compared to linked lists (as implemented by linklist.c),
109 * trees allow for much faster searching.
110 *
111 * Assuming a linked list contains N items, then searching a
112 * linked list for an item will take an average of N/2 comparisons
113 * and even N comparisons if the item cannot be found (unless
114 * you keep the list sorted, but linklist.c doesn't do this).
115 *
116 * According to "Algorithms in C", a search in a balanced
117 * "red-black" binary tree takes about lg N comparisons on
118 * average, and insertions take less than one rotation on
119 * average.
120 *
121 * Example: You need to build a list of files, and you
122 * will search the list frequently according to the file
123 * handles. This would make the handle an ideal "id" field.
124 *
125 * Differences compared to linklist.c:
126 *
127 * -- Trees are considerably slower when inserting and removing
128 * nodes because the tree has to be rebalanced every time
129 * a node changes. By contrast, trees are much faster finding
130 * nodes because the tree is always sorted.
131 *
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.
134 *
135 * -- As opposed to a LISTNODE, the TREE structure (which
136 * represents a tree node) does not contain a data pointer,
137 * as said above.
138 *
139 *@@added V0.9.5 (2000-09-29) [umoeller]
140 *@@header "helpers\tree.h"
141 */
142
143/*
144 * Written: 97/11/18 Jonathan Schultz <jonathan@imatix.com>
145 * Revised: 98/12/08 Jonathan Schultz <jonathan@imatix.com>
146 *
147 * Copyright (C) 1991-99 iMatix Corporation.
148 * Copyright (C) 2000 Ulrich M”ller.
149 * This file is part of the "XWorkplace helpers" source package.
150 * This is free software; you can redistribute it and/or modify
151 * it under the terms of the GNU General Public License as published
152 * by the Free Software Foundation, in version 2 as it comes in the
153 * "COPYING" file of the XWorkplace main distribution.
154 * This program is distributed in the hope that it will be useful,
155 * but WITHOUT ANY WARRANTY; without even the implied warranty of
156 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
157 * GNU General Public License for more details.
158 */
159
160/*
161 *@@category: Helpers\C helpers\Red-black balanced binary trees
162 * See tree.c.
163 */
164
165#include "setup.h"
166#include "helpers\tree.h"
167
168// Constants
169TREE TREE_EMPTY = {TREE_NULL, TREE_NULL, NULL, BLACK};
170
171// Internal function prototypes
172static void insert_fixup(TREE **root, TREE *tree);
173static void rotate_left(TREE **root, TREE *tree);
174static void rotate_right(TREE **root, TREE *tree);
175static void delete_fixup(TREE **root, TREE *tree);
176
177/*
178 *@@ treeInit:
179 * initializes an empty tree. The data on the
180 * tree will be invalid, and no memory will be
181 * freed.
182 *
183 * Usage:
184 + TREE *TreeRoot;
185 + treeInit(&TreeRoot);
186 */
187
188void treeInit(TREE **root)
189{
190 *root = TREE_NULL;
191}
192
193/*
194 * fnCompareIDs:
195 *
196 *added V0.9.9 (2001-02-06) [umoeller]
197 */
198
199int 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/*
209 *@@ treeInsertID:
210 * inserts a node into an existing tree.
211 *
212 * Note: A tree node MUST contain a TREE structure
213 * at the beginning for the tree functions to work.
214 * So to create a tree node with usable data, do this:
215 *
216 + typedef _MYTREENODE
217 + {
218 + // TREE must be at beginning
219 + TREE Tree;
220 + // now use whatever you want
221 + CHAR szMyExtraData[100];
222 + } MYTREENODE, *PMYTREENODE;
223 *
224 * When calling the tree functions, manually cast your
225 * MYTREENODE pointers to (TREE*).
226 *
227 * This function initialises the node pointers and colour
228 * in the TREE structure to correct values, so the caller
229 * does not have to worry about those.
230 *
231 * However you must initialize the TREE.id member correctly
232 * so that your comparison function can compare on that
233 * to find the correct place in the tree to insert the node.
234 *
235 * Usage:
236 + TREE *TreeRoot;
237 + treeInit(&TreeRoot);
238 +
239 + PMYTREENODE pTreeItem = malloc(sizeof(MYTREENODE));
240 + pTreeItem->Tree.id = 1;
241 +
242 + treeInsertID(&TreeRoot,
243 + (TREE*)pTreeItem,
244 + FALSE);
245 *
246 * Returns:
247 *
248 * -- TREE_OK: OK, item inserted.
249 *
250 * -- TREE_DUPLICATE: if (fAllowDuplicates == FALSE), this is
251 * returned if a tree item with the specified ID already
252 * exists.
253 *
254 *@@changed V0.9.9 (2001-02-06) [umoeller]: removed comparison func
255 */
256
257int treeInsertID(TREE **root, // in: root of tree
258 TREE *tree, // in: new tree node
259 BOOL fAllowDuplicates) // in: whether duplicates with the same ID are allowed
260{
261 TREE
262 *current,
263 *parent;
264 int
265 last_comp = 0;
266
267 // find where node belongs
268 current = *root;
269 parent = NULL;
270 while (current != TREE_NULL)
271 {
272 parent = current;
273 last_comp = fnCompareIDs(tree->id, current->id);
274 switch (last_comp)
275 {
276 case -1: current = current->left; break;
277 case 1: current = current->right; break;
278 default: if (fAllowDuplicates)
279 current = current->left;
280 else
281 return TREE_DUPLICATE;
282
283 }
284 }
285
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;
291
292 // insert node in tree
293 if (parent)
294 switch (last_comp)
295 {
296 case 1: parent->right = tree; break;
297 default: parent->left = tree;
298 }
299 else
300 *root = tree;
301
302 insert_fixup(root, tree);
303 return(TREE_OK);
304}
305
306/*
307 *@@ treeInsertNode:
308 * similar to treeInsertID, but this uses
309 * a comparision function which compares
310 * nodes.
311 */
312
313int treeInsertNode(TREE **root, // in: root of tree
314 TREE *tree, // in: new tree node
315 FNTREE_COMPARE_NODES *comp, // in: comparison function
316 BOOL fAllowDuplicates) // in: whether duplicates with the same ID are allowed
317{
318 TREE
319 *current,
320 *parent;
321 int
322 last_comp = 0;
323
324 // find where node belongs
325 current = *root;
326 parent = NULL;
327 while (current != TREE_NULL)
328 {
329 parent = current;
330 last_comp = comp(tree, current);
331 switch (last_comp)
332 {
333 case -1: current = current->left; break;
334 case 1: current = current->right; break;
335 default: if (fAllowDuplicates)
336 current = current->left;
337 else
338 return TREE_DUPLICATE;
339
340 }
341 }
342
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;
348
349 // insert node in tree
350 if (parent)
351 switch (last_comp)
352 {
353 case 1: parent->right = tree; break;
354 default: parent->left = tree;
355 }
356 else
357 *root = tree;
358
359 insert_fixup(root, tree);
360 return(TREE_OK);
361}
362
363/*
364 * insert_fixup:
365 * maintains the Red-Black tree balance after a node has been inserted.
366 *
367 * Private function.
368 */
369
370static void insert_fixup(TREE **root,
371 TREE *tree)
372{
373 TREE *uncle;
374
375 // check red-black properties
376 while ((tree != *root)
377 && (tree->parent->colour == RED))
378 {
379 // we have a violation
380 if (tree->parent == tree->parent->parent->left)
381 {
382 uncle = tree->parent->parent->right;
383 if (uncle->colour == RED)
384 {
385 // uncle is RED
386 tree ->parent->colour = BLACK;
387 uncle->colour = BLACK;
388 tree ->parent->parent->colour = RED;
389
390 tree = tree->parent->parent;
391 }
392 else
393 {
394 // uncle is BLACK
395 if (tree == tree->parent->right)
396 {
397 // make tree a left child
398 tree = tree->parent;
399 rotate_left (root, tree);
400 }
401
402 // recolor and rotate
403 tree->parent->colour = BLACK;
404 tree->parent->parent->colour = RED;
405 rotate_right (root, tree->parent->parent);
406 }
407 }
408 else
409 {
410 // mirror image of above code
411 uncle = tree->parent->parent->left;
412 if (uncle->colour == RED)
413 {
414 // uncle is RED
415 tree ->parent->colour = BLACK;
416 uncle->colour = BLACK;
417 tree ->parent->parent->colour = RED;
418
419 tree = tree->parent->parent;
420 }
421 else
422 {
423 // uncle is BLACK
424 if (tree == tree->parent->left)
425 {
426 tree = tree->parent;
427 rotate_right (root, tree);
428 }
429 tree->parent->colour = BLACK;
430 tree->parent->parent->colour = RED;
431 rotate_left (root, tree->parent->parent);
432 }
433 }
434 }
435 (*root)->colour = BLACK;
436}
437
438/*
439 * rotate_left:
440 * rotates tree to left.
441 *
442 * Private function.
443 */
444
445static void rotate_left(TREE **root,
446 TREE *tree)
447{
448 TREE *other = tree->right;
449
450 // establish tree->right link
451 tree->right = other->left;
452 if (other->left != TREE_NULL)
453 other->left->parent = tree;
454
455 // establish other->parent link
456 if (other != TREE_NULL)
457 other->parent = tree->parent;
458
459 if (tree->parent)
460 {
461 if (tree == tree->parent->left)
462 tree->parent->left = other;
463 else
464 tree->parent->right = other;
465 }
466 else
467 *root = other;
468
469 // link tree and other
470 other->left = tree;
471 if (tree != TREE_NULL)
472 tree->parent = other;
473}
474
475/*
476 * rotate_right:
477 * rotates tree to right.
478 *
479 * Private function.
480 */
481
482static void rotate_right(TREE **root,
483 TREE *tree)
484{
485 TREE *other;
486
487 other = tree->left;
488
489 // establish tree->left link
490 tree->left = other->right;
491 if (other->right != TREE_NULL)
492 other->right->parent = tree;
493
494 // establish other->parent link
495 if (other != TREE_NULL)
496 other->parent = tree->parent;
497
498 if (tree->parent)
499 {
500 if (tree == tree->parent->right)
501 tree->parent->right = other;
502 else
503 tree->parent->left = other;
504 }
505 else
506 *root = other;
507
508 // link tree and other
509 other->right = tree;
510 if (tree != TREE_NULL)
511 tree->parent = other;
512}
513
514/*
515 *@@ treeDelete:
516 * deletes a node from a tree. Does not deallocate any memory.
517 *
518 * Returns:
519 *
520 * -- TREE_OK: node deleted.
521 * -- TREE_INVALID_NODE: tree node not found.
522 */
523
524int treeDelete(TREE **root, // in: root of tree
525 TREE *tree) // in: tree node to delete
526{
527 int irc = TREE_OK;
528
529 TREE
530 *youngest, *descendent;
531 TREE_COLOUR
532 colour;
533
534 if ( (!tree)
535 || (tree == TREE_NULL)
536 )
537 return TREE_INVALID_NODE;
538
539 if ( (((TREE*)tree)->left == TREE_NULL)
540 || (((TREE*)tree)->right == TREE_NULL)
541 )
542 // descendent has a TREE_NULL node as a child
543 descendent = tree;
544 else
545 {
546 // find tree successor with a TREE_NULL node as a child
547 descendent = ((TREE*)tree)->right;
548 while (descendent->left != TREE_NULL)
549 descendent = descendent->left;
550 }
551
552 // youngest is descendent's only child, if there is one, else TREE_NULL
553 if (descendent->left != TREE_NULL)
554 youngest = descendent->left;
555 else
556 youngest = descendent->right;
557
558 // remove descendent from the parent chain
559 if (youngest != TREE_NULL)
560 youngest->parent = descendent->parent;
561 if (descendent->parent)
562 {
563 if (descendent == descendent->parent->left)
564 descendent->parent->left = youngest;
565 else
566 descendent->parent->right = youngest;
567 }
568 else
569 *root = youngest;
570
571 colour = descendent->colour;
572
573 if (descendent != (TREE *) tree)
574 {
575 // Conceptually what we are doing here is moving the data from
576 // descendent to tree. In fact we do this by linking descendent
577 // into the structure in the place of tree.
578 descendent->left = ((TREE*)tree)->left;
579 descendent->right = ((TREE*)tree)->right;
580 descendent->parent = ((TREE*)tree)->parent;
581 descendent->colour = ((TREE*)tree)->colour;
582
583 if (descendent->parent)
584 {
585 if (tree == descendent->parent->left)
586 descendent->parent->left = descendent;
587 else
588 descendent->parent->right = descendent;
589 }
590 else
591 *root = descendent;
592
593 if (descendent->left != TREE_NULL)
594 descendent->left->parent = descendent;
595
596 if (descendent->right != TREE_NULL)
597 descendent->right->parent = descendent;
598 }
599
600 if ( (youngest != TREE_NULL)
601 && (colour == BLACK))
602 delete_fixup (root, youngest);
603
604 return (irc);
605}
606
607/*
608 *@@ delete_fixup:
609 * maintains Red-Black tree balance after deleting a node.
610 *
611 * Private function.
612 */
613
614static void delete_fixup(TREE **root,
615 TREE *tree)
616{
617 TREE
618 *sibling;
619
620 while (tree != *root && tree->colour == BLACK)
621 {
622 if (tree == tree->parent->left)
623 {
624 sibling = tree->parent->right;
625 if (sibling->colour == RED)
626 {
627 sibling->colour = BLACK;
628 tree->parent->colour = RED;
629 rotate_left (root, tree->parent);
630 sibling = tree->parent->right;
631 }
632 if ((sibling->left->colour == BLACK)
633 && (sibling->right->colour == BLACK))
634 {
635 sibling->colour = RED;
636 tree = tree->parent;
637 }
638 else
639 {
640 if (sibling->right->colour == BLACK)
641 {
642 sibling->left->colour = BLACK;
643 sibling->colour = RED;
644 rotate_right (root, sibling);
645 sibling = tree->parent->right;
646 }
647 sibling->colour = tree->parent->colour;
648 tree->parent->colour = BLACK;
649 sibling->right->colour = BLACK;
650 rotate_left (root, tree->parent);
651 tree = *root;
652 }
653 }
654 else
655 {
656 sibling = tree->parent->left;
657 if (sibling->colour == RED)
658 {
659 sibling->colour = BLACK;
660 tree->parent->colour = RED;
661 rotate_right (root, tree->parent);
662 sibling = tree->parent->left;
663 }
664 if ((sibling->right->colour == BLACK)
665 && (sibling->left->colour == BLACK))
666 {
667 sibling->colour = RED;
668 tree = tree->parent;
669 }
670 else
671 {
672 if (sibling->left->colour == BLACK)
673 {
674 sibling->right->colour = BLACK;
675 sibling->colour = RED;
676 rotate_left (root, sibling);
677 sibling = tree->parent->left;
678 }
679 sibling->colour = tree->parent->colour;
680 tree->parent->colour = BLACK;
681 sibling->left->colour = BLACK;
682 rotate_right (root, tree->parent);
683 tree = *root;
684 }
685 }
686 }
687 tree->colour = BLACK;
688}
689
690/*
691 *@@ treeFindEQID:
692 * finds a node with ID exactly matching that provided.
693 */
694
695void* treeFindEQID(TREE **root,
696 unsigned long id)
697{
698 TREE
699 *current = *root,
700 *found;
701
702 found = NULL;
703 while (current != TREE_NULL)
704 switch (fnCompareIDs(current->id, id))
705 {
706 case -1: current = current->right; break;
707 case 1: current = current->left; break;
708 default: found = current; // In case of duplicates,
709 current = current->left; // get the first one.
710 }
711
712 return found;
713}
714
715/*
716 *@@ treeFindGEID:
717 * finds a node with ID greater than or equal to provided.
718 * To find a tree node, your comparison function must
719 * compare the tree node IDs.
720 */
721
722void* treeFindGEID(TREE **root,
723 unsigned long idFind)
724{
725 TREE
726 *current = *root,
727 *found;
728
729 found = NULL;
730 while (current != TREE_NULL)
731 switch (fnCompareIDs(current->id, idFind))
732 {
733 case -1: current = current->right; break;
734 default: found = current;
735 current = current->left;
736 }
737
738 return found;
739}
740
741/*
742 *@@ treeFindEQNode:
743 * finds a node with ID exactly matching that provided.
744 * To find a tree node, your comparison function must
745 * compare the tree nodes.
746 */
747
748void* treeFindEQNode(TREE **root,
749 TREE *nodeFind,
750 FNTREE_COMPARE_NODES *comp)
751{
752 TREE
753 *current = *root,
754 *found;
755
756 found = NULL;
757 while (current != TREE_NULL)
758 switch (comp(current, nodeFind))
759 {
760 case -1: current = current->right; break;
761 case 1: current = current->left; break;
762 default: found = current; // In case of duplicates,
763 current = current->left; // get the first one.
764 }
765
766 return found;
767}
768
769/*
770 *@@ treeFindGENode:
771 * finds a node with ID greater than or equal to provided.
772 * To find a tree node, your comparison function must
773 * compare the tree nodes.
774 */
775
776void* treeFindGENode(TREE **root,
777 TREE *nodeFind,
778 FNTREE_COMPARE_NODES *comp)
779{
780 TREE
781 *current = *root,
782 *found;
783
784 found = NULL;
785 while (current != TREE_NULL)
786 switch (comp(current, nodeFind))
787 {
788 case -1: current = current->right; break;
789 default: found = current;
790 current = current->left;
791 }
792
793 return found;
794}
795
796/*
797 *@@ treeFindLTNode:
798 * finds a node with Node less than provided.
799 * To find a tree node, your comparison function must
800 * compare the tree nodes.
801 */
802
803void* treeFindLTNode(TREE **root,
804 TREE *nodeFind,
805 FNTREE_COMPARE_NODES *comp)
806{
807 TREE
808 *current = *root,
809 *found;
810
811 found = NULL;
812 while (current != TREE_NULL)
813 switch (comp(current, nodeFind))
814 {
815 case -1: found = current;
816 current = current->right; break;
817 default: current = current->left;
818 }
819
820 return found;
821}
822
823/*
824 *@@ treeFindLENode:
825 * finds a node with Node less than or equal to provided.
826 * To find a tree node, your comparison function must
827 * compare the tree nodes.
828 */
829
830void* treeFindLENode(TREE **root,
831 TREE *nodeFind,
832 FNTREE_COMPARE_NODES *comp)
833{
834 TREE
835 *current = *root,
836 *found;
837
838 found = NULL;
839 while (current != TREE_NULL)
840 switch (comp(current, nodeFind))
841 {
842 case 1 : current = current->left; break;
843 default: found = current;
844 current = current->right;
845 }
846
847 return found;
848}
849
850/*
851 *@@ treeFindGTNode:
852 * finds a node with Node greater than provided.
853 * To find a tree node, your comparison function must
854 * compare the tree nodes.
855 */
856
857void* treeFindGTNode(TREE **root,
858 TREE *nodeFind,
859 FNTREE_COMPARE_NODES *comp)
860{
861 TREE
862 *current = *root,
863 *found;
864
865 found = NULL;
866 while (current != TREE_NULL)
867 switch (comp(current, nodeFind))
868 {
869 case 1 : found = current;
870 current = current->left; break;
871 default: current = current->right;
872 }
873
874 return found;
875}
876
877/*
878 *@@ treeFindEQID:
879 * finds a node with data exactly matching that provided.
880 * To find a tree node, your comparison function must
881 * compare a tree member with external data.
882 *
883 * This is useful for finding a tree item from a string ID.
884 *
885 * Make sure to use treeInsertNode and compare according
886 * to a string member, and then write a second compare
887 * function for this function which compares the string
888 * member to an external string.
889 */
890
891void* treeFindEQData(TREE **root,
892 void *pData,
893 FNTREE_COMPARE_DATA *comp)
894{
895 TREE *current = *root,
896 *found = NULL;
897
898 while (current != TREE_NULL)
899 switch (comp(current, pData))
900 {
901 case -1: current = current->right; break;
902 case 1: current = current->left; break;
903 default: found = current; // In case of duplicates,
904 current = current->left; // get the first one.
905 }
906
907 return found;
908}
909
910/*
911 *@@ treeTraverse:
912 * traverses the specified tree, calling a processing function
913 * for each tree node.
914 *
915 * The processing function ("process") must be declared as
916 * follows:
917 *
918 + void fnProcess(TREE *t, // current tree node
919 + void *pUser); // user data
920 *
921 * and will receive the "pUser" parameter, which you can use
922 * as a data pointer to some structure for whatever you like.
923 *
924 * "method" specifies in which order the nodes are traversed.
925 * This can be:
926 *
927 * -- 1: current node first, then left node, then right node.
928 * -- 2: left node first, then right node, then current node.
929 * -- 0 or other: left node first, then current node, then right node.
930 * This is the sorted order.
931 */
932
933void treeTraverse(TREE *tree, // in: root of tree
934 TREE_PROCESS *process, // in: callback for each node
935 void *pUser, // in: user param for callback
936 int method) // in: traversal mode
937{
938 if ((!tree)
939 || (tree == TREE_NULL))
940 return;
941
942 if (method == 1)
943 {
944 process(tree, pUser);
945 treeTraverse (((TREE*)tree)->left, process, pUser, method);
946 treeTraverse (((TREE*)tree)->right, process, pUser, method);
947 }
948 else if (method == 2)
949 {
950 treeTraverse (((TREE*)tree)->left, process, pUser, method);
951 treeTraverse (((TREE*)tree)->right, process, pUser, method);
952 process(tree, pUser);
953 }
954 else
955 {
956 treeTraverse (((TREE*)tree)->left, process, pUser, method);
957 process(tree, pUser);
958 treeTraverse (((TREE*)tree)->right, process, pUser, method);
959 }
960}
961
962/*
963 *@@ treeFirst:
964 * finds and returns the first node in a (sub-)tree.
965 */
966
967void* treeFirst(TREE *tree)
968{
969 TREE
970 *current;
971
972 if ((!tree)
973 || (tree == TREE_NULL))
974 return NULL;
975
976 current = tree;
977 while (current->left != TREE_NULL)
978 current = current->left;
979
980 return current;
981}
982
983/*
984 *@@ treeLast:
985 * finds and returns the last node in a (sub-)tree.
986 */
987
988void* treeLast(TREE *tree)
989{
990 TREE
991 *current;
992
993 if ((!tree)
994 || (tree == TREE_NULL))
995 return NULL;
996
997 current = tree;
998 while (current->right != TREE_NULL)
999 current = current->right;
1000
1001 return current;
1002}
1003
1004/*
1005 *@@ treeNext:
1006 * finds and returns the next node in a tree.
1007 */
1008
1009void* treeNext(TREE *tree)
1010{
1011 TREE
1012 *current,
1013 *child;
1014
1015 if ((!tree)
1016 || (tree == TREE_NULL))
1017 return NULL;
1018
1019 current = tree;
1020 if (current->right != TREE_NULL)
1021 return treeFirst (current->right);
1022 else
1023 {
1024 current = tree;
1025 child = TREE_NULL;
1026 while ((current->parent)
1027 && (current->right == child))
1028 {
1029 child = current;
1030 current = current->parent;
1031 }
1032 if (current->right != child)
1033 return current;
1034 else
1035 return NULL;
1036 }
1037}
1038
1039/*
1040 *@@ treePrev:
1041 * finds and returns the previous node in a tree.
1042 */
1043
1044void* treePrev(TREE *tree)
1045{
1046 TREE
1047 *current,
1048 *child;
1049
1050 if ((!tree)
1051 || (tree == TREE_NULL))
1052 return NULL;
1053
1054 current = tree;
1055 if (current->left != TREE_NULL)
1056 return treeLast (current->left);
1057 else
1058 {
1059 current = tree;
1060 child = TREE_NULL;
1061 while ((current->parent)
1062 && (current->left == child))
1063 {
1064 child = current;
1065 current = current->parent;
1066 }
1067 if (current->left != child)
1068 return current;
1069 else
1070 return NULL;
1071 }
1072}
1073
1074
Note: See TracBrowser for help on using the repository browser.