home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progc / ctools10.arj / AVL.C next >
C/C++ Source or Header  |  1991-12-31  |  30KB  |  1,051 lines

  1. /****************************************************************************
  2. *
  3. *                    Copyright (C) 1991 Kendall Bennett.
  4. *                            All rights reserved.
  5. *
  6. * Filename:        $RCSfile: avl.c $
  7. * Version:        $Revision: 1.3 $
  8. *
  9. * Language:        ANSI C
  10. * Environment:    any
  11. *
  12. * Description:    Module to implement balanced AVL trees.
  13. *
  14. * $Id: avl.c 1.3 91/12/31 19:40:43 kjb Exp $
  15. *
  16. * Revision History:
  17. * -----------------
  18. *
  19. * $Log:    avl.c $
  20. * Revision 1.3  91/12/31  19:40:43  kjb
  21. * Modified include file directories
  22. * Revision 1.2  91/09/27  03:10:00  kjb
  23. * Added stuff keep track of the number of nodes in the tree.
  24. * Revision 1.1  91/09/27  02:50:49  kjb
  25. * Initial revision
  26. ****************************************************************************/
  27.  
  28. #include <stdio.h>
  29. #include <malloc.h>
  30. #include <signal.h>
  31. #include "debug.h"
  32. #include "avl.h"
  33.  
  34. /*--------------------------- Globals Variables ---------------------------*/
  35.  
  36. PRIVATE AVL_TREE    *Tree;        /* Pointer to tree we are working with    */
  37. PRIVATE    AVL_BUCKET    *Node;        /* Pointer to node we are working with    */
  38. PRIVATE void        *Conflicting;    /* Conflicting node                 */
  39. PRIVATE bool        Notfound;    /* Flags if a node cannot be found        */
  40. PRIVATE void         (*Visit)(void*,void*);
  41. PRIVATE void        (*Prnt)(FILE*,void*);
  42. PRIVATE    void        *Params,*Lower,*Upper;
  43. PRIVATE    FILE*        Out;
  44. PRIVATE char        Map[MAXLEVEL / 8];
  45. PRIVATE    char        *Graph_chars[] = { "│","┌──","└──","──┤","──┘","──┐"};
  46. PRIVATE    char        *Norm_chars[] = { "|","+--","+--","--+","--+","--+"};
  47. PRIVATE    char        **Cset;
  48.  
  49. /*----------------------------- Implementation ----------------------------*/
  50.  
  51. PUBLIC void *avl_newnode(int size)
  52. /****************************************************************************
  53. *
  54. * Function:        avl_newnode
  55. * Parameters:    size    - Amount of memory to allocate for node
  56. * Returns:        Pointer to the allocated nodes user space.
  57. *
  58. * Description:    Allocates the memory required for a node, adding a small
  59. *                header at the start of the node. We return a reference to
  60. *                the user space of the node, as if it had be allocated via
  61. *                malloc.
  62. *
  63. ****************************************************************************/
  64. {
  65.     AVL_BUCKET    *n;
  66.  
  67.     if ( !(n = (AVL_BUCKET*)malloc(size+sizeof(AVL_BUCKET))) ) {
  68.         fprintf(stderr,"Can't get memory for BUCKET\n");
  69.         raise(SIGABRT);
  70.         return NULL;
  71.         }
  72.  
  73.     return AVL_USERSPACE(n);        /* Return pointer to user space        */
  74. }
  75.  
  76. /*-------------------------------------------------------------------------*/
  77.  
  78. PUBLIC void avl_freenode(void *node)
  79. /****************************************************************************
  80. *
  81. * Function:        avl_freesym
  82. * Parameters:    node    - Node to free
  83. *
  84. * Description:    Frees a node previously allocated with avl_newsym().
  85. *
  86. ****************************************************************************/
  87. {
  88.     free(AVL_HEADER(node));
  89. }
  90.  
  91. /*-------------------------------------------------------------------------*/
  92.  
  93. PUBLIC AVL_TREE *avl_init(int (*cmp_function)(void*,void*))
  94. /****************************************************************************
  95. *
  96. * Function:        avl_init
  97. * Parameters:    cmp_function    - Function to compare the value of two nodes
  98. *                prnt_function    - Function to print the value of a node
  99. * Returns:        Pointer to the newly created AVL tree.
  100. *
  101. * Description:    Makes a new AVL tree with no elements and returns a pointer
  102. *                to it.
  103. *
  104. ****************************************************************************/
  105. {
  106.     AVL_TREE    *tree;
  107.  
  108.     if( (tree = (AVL_TREE*)malloc(sizeof(AVL_TREE))) != NULL) {
  109.         tree->count = 0;
  110.         tree->cmp = cmp_function;
  111.         tree->root = NULL;
  112.         }
  113.     else {
  114.         fprintf(stderr,"Insufficient memory for AVL tree\n");
  115.         raise(SIGABRT);
  116.         return NULL;
  117.         }
  118.     return tree;
  119. }
  120.  
  121. /*-------------------------------------------------------------------------*/
  122.  
  123. PRIVATE void (*_freeNode)(void*);
  124.  
  125. PRIVATE void free_subtree(AVL_BUCKET *t)
  126. /****************************************************************************
  127. *
  128. * Function:        free_subtree
  129. * Parameters:    t    - Subtree to free
  130. *
  131. * Description:    Recursive routine to free the elements of a particular
  132. *                subtree.
  133. *
  134. ****************************************************************************/
  135. {
  136.     if (t) {
  137.         free_subtree(t->left);
  138.         free_subtree(t->right);
  139.         _freeNode(AVL_USERSPACE(t));
  140.         }
  141. }
  142.  
  143. PUBLIC void avl_empty(AVL_TREE *t,void (*freeNode)(void*))
  144. /****************************************************************************
  145. *
  146. * Function:        avl_empty
  147. * Parameters:    t            - Tree to kill
  148. *                freeNode    - Routine to free each node of the tree
  149. *
  150. * Description:    Deletes the entire AVL tree from memory including all the
  151. *                nodes of the tree. We call the user supplied routine
  152. *                freeNode() to free each node in the tree. This allows the
  153. *                user program to perform any extra processing that is
  154. *                required to kill each node (for example if they contain
  155. *                pointers to other items on the heap). If no extra
  156. *                processing is required, just pass the address of
  157. *                avl_freenode(), ie:
  158. *
  159. *                    avl_kill(myTree,avl_freenode);
  160. *
  161. ****************************************************************************/
  162. {
  163.     _freeNode = freeNode;
  164.     free_subtree(t->root);
  165.     t->root = NULL;
  166. }
  167.  
  168. /*-------------------------------------------------------------------------*/
  169.  
  170. PRIVATE void insert(AVL_BUCKET **pp)
  171. /****************************************************************************
  172. *
  173. * Function:        insert
  174. * Parameters:    pp    - Pointer to pointer to root of subtree to insert into
  175. *
  176. * Description:    Internal recursive routine to insert a node into an
  177. *                AVL tree. Expects the global variables Tree, and Node
  178. *                to be set up. If we encounter a duplicate key, we return
  179. *                the address of this key in the global Conflicting;
  180. *
  181. ****************************************************************************/
  182. {
  183.     AVL_BUCKET    *p = *pp;
  184.     AVL_BUCKET    *p1,*p2;
  185.     int            relation;    /* Relationship between root and Node        */
  186.     static bool    h = 0;            /* Set to indicate that subtree has grown    */
  187.  
  188.     if (p == NULL) {
  189.  
  190.         /* We have found a valid spot for the node, so insert it and
  191.          * let the higher level recursions know that the tree has
  192.          * subsequently grown.
  193.          */
  194.  
  195.         p = Node;
  196.         p->left = p->right = NULL;
  197.         p->bal = BAL;
  198.         h = true;
  199.         }
  200.     else if ((relation = Tree->cmp(AVL_USERSPACE(p),
  201.             AVL_USERSPACE(Node))) == 0) {
  202.  
  203.         /* We have a node with a duplicate key that we cannot insert
  204.          * into the tree. We return the address of the user space for
  205.          * the node in the global Conflicting
  206.          */
  207.  
  208.         Conflicting = AVL_USERSPACE(p);
  209.         h = false;
  210.         }
  211.     else if (relation > 0) {
  212.  
  213.         /* If relation is > 0, then the current node p is greater than
  214.          * Node, so we insert the node into the left subtree.
  215.          */
  216.  
  217.         insert(&p->left);
  218.  
  219.         if (h) {                /* The left subtree has grown in height    */
  220.             switch (p->bal) {
  221.                 case LH:
  222.  
  223.                     /* The left subtree has grown taller than it is allowed,
  224.                      * so we must perform a rebalance of the tree.
  225.                      */
  226.  
  227.                     p1 = p->left;
  228.                     if (p1->bal == LH) {
  229.  
  230.                         /* Left subtree is LEFTHIGH, so we need to do a
  231.                          * single right rotation to rebalance the subtree p.
  232.                          */
  233.  
  234.                         p->left = p1->right;
  235.                         p1->right = p;
  236.                         p->bal = BAL;
  237.                         p = p1;
  238.                         }
  239.                     else {
  240.  
  241.                         /* Left subtree is RIGHTHIGH, so we need to do a
  242.                          * double right rotation to rebalance the subtree p.
  243.                          */
  244.  
  245.                         p2 = p1->right;
  246.                         p1->right = p2->left;
  247.                         p2->left = p1;
  248.                         p->left = p2->right;
  249.                         p2->right = p;
  250.                         p->bal = (p2->bal == LH) ? RH : BAL;
  251.                         p1->bal = (p2->bal == RH) ? LH : BAL;
  252.                         p = p2;
  253.                         }
  254.                     p->bal = BAL;            /* Tree is now balanced        */
  255.                     h = 0;
  256.                     break;
  257.                 case BAL:
  258.  
  259.                     /* The subtree was previously balanced, so now it
  260.                      * simply becomes LEFTHIGH.
  261.                      */
  262.  
  263.                     p->bal = LH;
  264.                     break;
  265.                 case RH:
  266.  
  267.                     /* The subtree was previously RIGHTHIGH, so now it
  268.                      * has become balanced. In this case the height of this
  269.                      * particular subtree has not grown, so h is reset to
  270.                      * false.
  271.                      */
  272.  
  273.                     p->bal = BAL;
  274.                     h = false;
  275.                 }
  276.             }
  277.         }
  278.     else {
  279.  
  280.         /* Relation was < 0, indicating that the current node p is smaller
  281.          * than Node, so we insert the new node into the right subtree.
  282.          */
  283.  
  284.         insert(&p->right);
  285.  
  286.         if (h) {            /* The right subtree has grown in height    */
  287.             switch (p->bal) {
  288.                 case LH:
  289.  
  290.                     /* The subtree was previously LEFTHIGH, so now it
  291.                      * has become balanced. In this case the height of this
  292.                      * particular subtree has not grown, so h is reset to
  293.                      * false.
  294.                      */
  295.  
  296.                     p->bal = BAL;
  297.                     h = false;
  298.                     break;
  299.                 case BAL:
  300.  
  301.                     /* The subtree was previously balanced, so now it
  302.                      * simply becomes RIGHTHIGH.
  303.                      */
  304.  
  305.                     p->bal = RH;
  306.                     break;
  307.                 case RH:
  308.  
  309.                     /* The right subtree has grown taller than it is allowed,
  310.                      * so we must perform a rebalance of the tree.
  311.                      */
  312.  
  313.                     p1 = p->right;
  314.                     if (p1->bal == RH) {
  315.  
  316.                         /* Right subtree is RIGHTHIGH, so we need to do a
  317.                          * single left rotation to rebalance the subtree p.
  318.                          */
  319.  
  320.                         p->right = p1->left;
  321.                         p1->left = p;
  322.                         p->bal = BAL;
  323.                         p = p1;
  324.                         }
  325.                     else {
  326.  
  327.                         /* Right subtree is LEFTHIGH, so we need to do a
  328.                          * double left rotation to rebalance the subtree p.
  329.                          */
  330.  
  331.                         p2 = p1->left;
  332.                         p1->left = p2->right;
  333.                         p2->right = p1;
  334.                         p->right = p2->left;
  335.                         p2->left = p;
  336.                         p->bal = (p2->bal == RH) ? LH : BAL;
  337.                         p1->bal = (p2->bal == LH) ? RH : BAL;
  338.                         p = p2;
  339.                         }
  340.                     p->bal = BAL;            /* Tree is now balanced        */
  341.                     h = 0;
  342.                 }
  343.             }
  344.         }
  345.  
  346.     /* Reset the root of this subtree to the new root p, since it may have
  347.      * changed during a rotate of the tree.
  348.      */
  349.  
  350.     *pp = p;
  351. }
  352.  
  353. PUBLIC void *avl_insert(AVL_TREE *tree,void *node)
  354. /****************************************************************************
  355. *
  356. * Function:        avl_insert
  357. * Parameters:    tree    - Tree to insert the node into
  358. *                node    - New node to insert into the tree
  359. * Returns:        NULL on success, or a pointer to the conflicting node.
  360. *
  361. * Description:    Inserts a new node into an AVL tree. Duplicate keys are
  362. *                currently not supported.
  363. *
  364. ****************************************************************************/
  365. {
  366.     Tree = tree;
  367.     Node = AVL_HEADER(node);
  368.     Conflicting = NULL;
  369.  
  370.     insert(&tree->root);
  371.     if (!Conflicting)    tree->count++;
  372.  
  373.     return Conflicting;
  374. }
  375.  
  376. /*-------------------------------------------------------------------------*/
  377.  
  378. PRIVATE bool balance_left(AVL_BUCKET **pp)
  379. /****************************************************************************
  380. *
  381. * Function:        balance_left
  382. * Parameters:    pp    - Point to root of subtree to balance
  383. * Returns:        True if the entire subtree shrank, false if not
  384. *
  385. * Description:    Routine to rebalance the subtree pointed to by pp when its
  386. *                left subtree has just shrunk. We adjust the balance factors
  387. *                and rebalance the subtree adjusting pp to point to the
  388. *                new root of the subtree.
  389. *
  390. ****************************************************************************/
  391. {
  392.     AVL_BUCKET    *p,*p1,*p2;
  393.     short        b1,b2;
  394.     bool        subtree_shrank = true;
  395.  
  396.     p = *pp;
  397.     switch (p->bal) {
  398.         case LH:
  399.  
  400.             /* The subtree was previously left high. Since the left subtree
  401.              * just shrank, this tree is now balanced while the overall
  402.              * height has been reduced.
  403.              */
  404.  
  405.             p->bal = BAL;
  406.             break;
  407.         case BAL:
  408.  
  409.             /* The subtree was previously balanced, so we simply make
  410.              * it right high, and signal that it did not shrink.
  411.              */
  412.  
  413.             p->bal = RH;
  414.             subtree_shrank = false;
  415.             break;
  416.         case RH:
  417.  
  418.             /* The subtree was previously right high. In this case we must do
  419.              * either a single or double left rotation. If the right
  420.              * subtree was balanced or right high, we only need a single
  421.              * left rotation. We do a double left rotate if the right subtree
  422.              * was left high.
  423.              */
  424.  
  425.             p1 = p->right;
  426.             b1 = p1->bal;
  427.             if (b1 >= BAL) {
  428.                 p->right = p1->left;        /* Single left rotatation    */
  429.                 p1->left = p;
  430.                 if (b1 == RH)
  431.                     p->bal = p1->bal = BAL;
  432.                 else {
  433.                     p->bal = RH;
  434.                     p1->bal = LH;
  435.                     subtree_shrank = false;
  436.                     }
  437.                 p = p1;                    /* Right subtree is new root    */
  438.                 }
  439.             else {
  440.                 p2 = p1->left;                /* Double left rotation        */
  441.                 b2 = p2->bal;
  442.                 p1->left = p2->right;
  443.                 p2->right = p1;
  444.                 p->right = p2->left;
  445.                 p2->left = p;
  446.                 p->bal = (b2 == RH) ? LH : BAL;
  447.                 p1->bal = (b2 == LH) ? RH : BAL;
  448.                 p2->bal = BAL;
  449.                 p = p2;
  450.                 }
  451.         }
  452.     *pp = p;
  453.     return subtree_shrank;
  454. }
  455.  
  456. PRIVATE bool balance_right(AVL_BUCKET **pp)
  457. /****************************************************************************
  458. *
  459. * Function:        balance_right
  460. * Parameters:    pp    - Point to root of subtree to balance
  461. * Returns:        True if the entire subtree shrank, false if not
  462. *
  463. * Description:    Routine to rebalance the subtree pointed to by pp when its
  464. *                right subtree has just shrunk. We adjust the balance factors
  465. *                and rebalance the subtree adjusting pp to point to the
  466. *                new root of the subtree.
  467. *
  468. ****************************************************************************/
  469. {
  470.     AVL_BUCKET    *p,*p1,*p2;
  471.     short        b1, b2;
  472.     bool        subtree_shrank = true;
  473.  
  474.     p = *pp;
  475.     switch (p->bal) {
  476.         case RH:
  477.  
  478.             /* The subtree was previously right high. Since the right subtree
  479.              * just shrank, this tree is now balanced while the overall
  480.              * height has been reduced.
  481.              */
  482.  
  483.             p->bal = BAL;
  484.             break;
  485.         case BAL:
  486.  
  487.             /* The subtree was previously balanced, so we simply make
  488.              * it right high, and signal that it did not shrink.
  489.              */
  490.  
  491.             p->bal = LH;
  492.             subtree_shrank = false;
  493.             break;
  494.         case LH:
  495.  
  496.             /* The subtree was previously left high. In this case we must do
  497.              * either a single or double right rotation. If the left
  498.              * subtree was balanced or left high, we only need a single
  499.              * right rotation. We do a double right rotate if the left
  500.              * subtree was right high.
  501.              */
  502.  
  503.             p1 = p->left;
  504.             b1 = p1->bal;
  505.             if (b1 <= BAL) {
  506.                 p->left = p1->right;        /* Single right rotation    */
  507.                 p1->right = p;
  508.                 if (b1 == LH)
  509.                     p->bal = p1->bal = BAL;
  510.                 else {
  511.                     p->bal = LH;
  512.                     p1->bal = RH;
  513.                     subtree_shrank = true;
  514.                     }
  515.                 p = p1;
  516.                 }
  517.             else {
  518.                 p2 = p1->right;                /* Double right rotation    */
  519.                 b2 = p2->bal;
  520.                 p1->right = p2->left;
  521.                 p2->left = p1;
  522.                 p->left = p2->right;
  523.                 p2->right = p;
  524.                 p->bal = (b2 == LH) ? LH : BAL;
  525.                 p1->bal = (b2 == RH) ? RH : BAL;
  526.                 p2->bal = BAL;
  527.                 p = p2;
  528.                 }
  529.         }
  530.     *pp = p;
  531.     return subtree_shrank;
  532. }
  533.  
  534. PRIVATE bool descend(AVL_BUCKET **rootp,AVL_BUCKET **pp)
  535. /****************************************************************************
  536. *
  537. * Function:        descend
  538. * Parameters:    rootp    - Pointer to pointer to tree to descend
  539. *                pp        - Pointer to pointer to node to replace
  540. * Returns:        True if the subtree just shrank, false if not.
  541. *
  542. * Description:    Routine to descend to the rightmost node of the left
  543. *                subtree. When we get there, we move it up into the position
  544. *                occupied by pp (retaining pp's balance factor) and delete
  545. *                this node. On the way back we rebalance the tree if
  546. *                necessary.
  547. *
  548. ****************************************************************************/
  549. {
  550.     AVL_BUCKET    *p = *rootp;
  551.     bool        has_shrunk,was_left = 0;
  552.  
  553.     if (p->right) {
  554.  
  555.         /* Continue to descend the right subtree, until we can go no
  556.          * further. On the way back up the recursion, if the tree has
  557.          * shrunk, we rebalance it.
  558.          */
  559.  
  560.         if (rootp == &(*pp)->left)
  561.             was_left = true;
  562.         has_shrunk = descend(&p->right,pp);
  563.         if (was_left)
  564.             rootp = &(*pp)->left;
  565.         return has_shrunk ? balance_right(rootp) : 0;
  566.         }
  567.     else {
  568.         *rootp = p->left;            /* Kill the old link to p            */
  569.  
  570.         p->bal = (*pp)->bal;        /* Retain the old balance factor    */
  571.         p->left = (*pp)->left;        /* and links                        */
  572.         p->right = (*pp)->right;
  573.         Node = *pp;                    /* Free the node                    */
  574.         *pp = p;                    /* Replace with p                    */
  575.         return true;                /* Subtree has shrunk - rebalance    */
  576.         }
  577. }
  578.  
  579. PRIVATE bool delete(AVL_BUCKET **pp)
  580. /****************************************************************************
  581. *
  582. * Function:        delete
  583. * Parameters:    pp    - Pointer to pointer to root of subtree to delete from
  584. * Returns:        True if the subtree shrunk in size, false if not.
  585. *
  586. * Description:    Internal recursive routine to delete a node from an
  587. *                AVL tree. Expects the global variables Tree, and Node
  588. *                to be set up. If the node is not found, we set the global
  589. *                Notfound to true.
  590. *
  591. ****************************************************************************/
  592. {
  593.     AVL_BUCKET    *p = *pp;
  594.     int            relation;
  595.  
  596.     if (p == NULL) {
  597.  
  598.         /* We could not locate the node in the tree, so set Notfound to
  599.          * true.
  600.          */
  601.  
  602.         Notfound = true;
  603.         return false;
  604.         }
  605.     else if ((relation = Tree->cmp(AVL_USERSPACE(p),
  606.             AVL_USERSPACE(Node))) == 0) {
  607.  
  608.         /* We have found the node, so delete it from the tree.
  609.          */
  610.  
  611.         if (p->right == NULL) {
  612.  
  613.             /* There is only a single left node in the tree, so move this
  614.              * node up to where p used to be, and then delete p.
  615.              */
  616.  
  617.             *pp = p->left;
  618.             Node = p;
  619.             return true;
  620.             }
  621.         else if (p->left == NULL) {
  622.  
  623.             /* There is only a single right node in the tree, so move this
  624.              * node up to where p used to be, and then delete p.
  625.              */
  626.  
  627.             *pp = p->right;
  628.             Node = p;
  629.             return true;
  630.             }
  631.         else if (descend(&p->left,pp))
  632.             return balance_left(pp);
  633.         }
  634.     else if (relation > 0) {
  635.  
  636.         /* If relation is > 0, then the current node p is greater than
  637.          * Node, so we delete node from the left subtree. If the left
  638.          * subtree has shrunk in size, we rebalance the tree and return
  639.          * the result of this rebalance (tree shrunk, or stayed the same
  640.          * size).
  641.          */
  642.  
  643.         if (delete(&p->left))
  644.             return balance_left(pp);
  645.         }
  646.     else {
  647.  
  648.         /* If relation is < 0, then the current node p is less than
  649.          * Node, so we delete node from the right subtree. If the right
  650.          * subtree has shrunk in size, we rebalance the tree and return
  651.          * the result of this rebalance (tree shrunk, or stayed the same
  652.          * size).
  653.          */
  654.  
  655.         if (delete(&p->right))
  656.             return balance_right(pp);
  657.         }
  658.     return false;
  659. }
  660.  
  661. PUBLIC void *avl_delete(AVL_TREE *tree,void *node)
  662. /****************************************************************************
  663. *
  664. * Function:        avl_delete
  665. * Parameters:    tree    - Tree to delete node from
  666. *                node    - Node to delete from tree
  667. * Returns:        Pointer to the node if successful, NULL of failure
  668. *
  669. * Description:    Deletes a node from an AVL tree. The node is removed from
  670. *                the tree, but it's memory is not released. You must call
  671. *                avl_freenode() to free the nodes memory.
  672. *
  673. ****************************************************************************/
  674. {
  675.     Tree = tree;
  676.     Node = AVL_HEADER(node);
  677.     Notfound = false;
  678.  
  679.     delete(&tree->root);
  680.     if (!Notfound)    tree->count--;
  681.  
  682.     return Notfound ? NULL : AVL_USERSPACE(Node);
  683. }
  684.  
  685. /*-------------------------------------------------------------------------*/
  686.  
  687. PRIVATE void pre_order(AVL_BUCKET *p)
  688. {
  689.     if (p) {
  690.         Visit(Params,AVL_USERSPACE(p));
  691.         pre_order(p->left);
  692.         pre_order(p->right);
  693.         }
  694. }
  695.  
  696. PRIVATE void in_order(AVL_BUCKET *p)
  697. {
  698.     if (p) {
  699.         in_order(p->left);
  700.         Visit(Params,AVL_USERSPACE(p));
  701.         in_order(p->right);
  702.         }
  703. }
  704.  
  705. PRIVATE void post_order(AVL_BUCKET *p)
  706. {
  707.     if (p) {
  708.         post_order(p->left);
  709.         post_order(p->right);
  710.         Visit(Params,AVL_USERSPACE(p));
  711.         }
  712. }
  713.  
  714. PUBLIC void avl_traverse(AVL_TREE *tree,int order,void (*visit)(void*,void*),
  715.     void *params)
  716. /****************************************************************************
  717. *
  718. * Function:        avl_preorder
  719. * Parameters:    tree    - Tree to traverse
  720. *
  721. * Description:    Traverses the AVL tree in a pre-order fashion, visiting
  722. *                the node first, then the left and then the right subtree.
  723. *
  724. *                The function visit() must accept two parameters. The second
  725. *                is a pointer to the node to visit, while the first is the
  726. *                params argument passed to avl_traverse.
  727. *
  728. ****************************************************************************/
  729. {
  730.     Visit = visit;
  731.     Params = params;
  732.     switch (order) {
  733.         case PREORDER:
  734.             pre_order(tree->root);
  735.             break;
  736.         case INORDER:
  737.             in_order(tree->root);
  738.             break;
  739.         case POSTORDER:
  740.             post_order(tree->root);
  741.         }
  742. }
  743.  
  744. /*-------------------------------------------------------------------------*/
  745.  
  746. /* Macro to test if the depth bit for level c is set    */
  747.  
  748. #define testbit(level)    (Map[level >> 3] & (1 << (level & 0x07)))
  749.  
  750. #ifdef DEBUG
  751. #define  PAD()    fprintf(Out,"   ");
  752. #define  PBAL(r)  fprintf(Out,"(%c)", r->bal == BAL ? 'B' : r->bal==LH ? 'L' : 'R');
  753. #else
  754. #define  PAD()
  755. #define  PBAL(r)
  756. #endif
  757.  
  758. PRIVATE void setbit(int level,bool set_it)
  759. /****************************************************************************
  760. *
  761. * Function:        setbit
  762. * Parameters:    depth    - Depth of bit to set
  763. *                set_it    - True to set bit, false to reset it
  764. *
  765. * Description:    Sets or resets the depth bit for a level. If this bit is
  766. *                set, we we draw a vertical line at that depth level.
  767. *
  768. ****************************************************************************/
  769. {
  770.     if (set_it)
  771.         Map[level >> 3] |= 1 << (level & 0x07);
  772.     else
  773.         Map[level >> 3] &= ~(1 << (level & 0x07));
  774. }
  775.  
  776. PRIVATE void print_tree(AVL_BUCKET *root,int left_subtree)
  777. /****************************************************************************
  778. *
  779. * Function:        print_tree
  780. * Parameters:    root            - Root of subtree to display
  781. *                left_subtree    - True if this is a left subtree
  782. *
  783. * Description:    Dumps the contents of subtree 'root' to the file Out.
  784. *
  785. ****************************************************************************/
  786. {
  787.     static int    depth = -1;            /* Current depth within subtree        */
  788.     int            i;
  789.  
  790.     if (root) {
  791.         depth++;
  792.  
  793.         if(root->right)
  794.             print_tree(root->right,false);
  795.         else
  796.             setbit(depth+1,true);
  797.  
  798.         for(i = 1; i <= depth; i++) {
  799.             Prnt(Out,NULL);
  800.             PAD();
  801.  
  802.             if (i == depth)
  803.                 fprintf(Out,"  %s", left_subtree ? Cset[2] : Cset[1]);
  804.             else if(testbit(i))
  805.                 fprintf(Out,"  %s  ", Cset[0]);
  806.             else
  807.                 fprintf(Out,"     ");
  808.             }
  809.  
  810.         Prnt(Out,AVL_USERSPACE(root));
  811.         PBAL(root);
  812.         fprintf(Out,"%s\n",root->left ? (root->right ? Cset[3] : Cset[5]) :
  813.             (root->right ? Cset[4] : ""));
  814.  
  815.         setbit(depth,left_subtree ? false : true);
  816.  
  817.         if(root->left)
  818.             print_tree(root->left,true);
  819.         else
  820.             setbit(depth+1,false);
  821.         depth--;
  822.         }
  823. }
  824.  
  825. PUBLIC void avl_print(FILE *out,AVL_TREE *tree,void (*prnt)(FILE*,void*),
  826.     bool graph_chars)
  827. /****************************************************************************
  828. *
  829. * Function:        avl_print
  830. * Parameters:    out                - Stream to print to
  831. *                tree            - Tree to print out
  832. *                prnt            - Routine to print each node
  833. *                graph_chars        - True if we print with graphics characters
  834. *
  835. * Description:    Dumps the contents of the AVL tree to the specified file.
  836. *                If graph_chars is true, the structure of the tree is
  837. *                printed using IBM graphics characters, otherwise it is
  838. *                printed using standard ASCII characters. If show_balance
  839. *                is true, the balance factors are displayed.
  840. *
  841. *                The routine prnt() takes a pointer to a file to print the
  842. *                node to, and a pointer to the node to print. It must print
  843. *                every node in a field of the same width, and when passed
  844. *                a null pointer for the node it should print a blank field
  845. *                the same width as the nodes. This provides correct
  846. *                formatting for the printed tree.
  847. *
  848. *                The tree can have a maximum height of 64 levels. If the
  849. *                tree is taller than this, the result is undefined. A
  850. *                balanced AVL tree with 64 levels would have in the order
  851. *                of 1e19 nodes!
  852. *
  853. ****************************************************************************/
  854. {
  855.     Tree = tree;
  856.     Out = out;
  857.     Prnt = prnt;
  858.     Cset = graph_chars ? Graph_chars : Norm_chars;
  859.     print_tree(tree->root,false);
  860. }
  861.  
  862. /*-------------------------------------------------------------------------*/
  863.  
  864. PUBLIC void *avl_findsym(AVL_TREE *tree,void *node)
  865. /****************************************************************************
  866. *
  867. * Function:        avl_findsym
  868. * Parameters:    tree    - Tree to search for the symbol
  869. *                node    - Node containing key to search for
  870. * Returns:        Pointer to the node if found, NULL if not.
  871. *
  872. * Description:    Searches the AVL tree for the specified node and returns
  873. *                it if it is found.
  874. *
  875. ****************************************************************************/
  876. {
  877.     AVL_BUCKET    *p;
  878.     int            relation;
  879.  
  880.     p = tree->root;
  881.  
  882.     while (p) {
  883.         if ((relation = tree->cmp(node,AVL_USERSPACE(p))) == 0)
  884.             return AVL_USERSPACE(p);
  885.         else if (relation > 0)
  886.             p = p->right;
  887.         else
  888.             p = p->left;
  889.         }
  890.     return NULL;
  891. }
  892.  
  893. /*-------------------------------------------------------------------------*/
  894.  
  895. PRIVATE void range_search(AVL_BUCKET *root)
  896. /****************************************************************************
  897. *
  898. * Function:        range_search
  899. * Parameters:    root    - Root of subtree to range search
  900. *
  901. * Description:    Recursive routine to range search a subtree.
  902. *
  903. ****************************************************************************/
  904. {
  905.     if (root) {
  906.         if (Tree->cmp(AVL_USERSPACE(root),Lower) < 0) {
  907.             /* If the root node is smaller than the lower bound, then recurse
  908.              * down the right subtree.
  909.              */
  910.  
  911.             range_search(root->right);
  912.             }
  913.         else if (Tree->cmp(AVL_USERSPACE(root),Upper) > 0) {
  914.             /* If the root node is larger than the lower bound, then recurse
  915.              * down the left subtree.
  916.              */
  917.  
  918.             range_search(root->left);
  919.             }
  920.         else {
  921.             /* We are within the range so recurse down the left subtree,
  922.              * visit the node and then recurse down the right subtree.
  923.              */
  924.  
  925.             range_search(root->left);
  926.             Visit(Params,AVL_USERSPACE(root));
  927.             range_search(root->right);
  928.             }
  929.         }
  930. }
  931.  
  932. PUBLIC void avl_range(AVL_TREE *tree,void *lower,void *upper,
  933.     void (*visit)(void*,void*),void *params)
  934. /****************************************************************************
  935. *
  936. * Function:        avl_range
  937. * Parameters:    tree    - Tree to range search
  938. *                lower    - Lower bound of range search (inclusive)
  939. *                upper    - Upper bound of range search (inclusive)
  940. *                visit    - Function to visit each node in range
  941. *                params    - Parameters for the visit routine.
  942. *
  943. * Description:    Calls visit for every node in the range [lower,upper]
  944. *                for the AVL tree 'tree'. Visit must accept two parameters.
  945. *                The first is the params argument passed to this function,
  946. *                while the second is a pointer to the node to visit.
  947. *
  948. ****************************************************************************/
  949. {
  950.     Tree = tree;
  951.     Visit = visit;
  952.     Params = params;
  953.     Lower = lower;
  954.     Upper = upper;
  955.     range_search(tree->root);
  956. }
  957.  
  958. /*-------------------------------------------------------------------------*/
  959.  
  960. int delmin(AVL_BUCKET **pp)
  961. /****************************************************************************
  962. *
  963. * Function:        delmin
  964. * Parameters:    root    - Root of subtree to delete from
  965. * Returns:        True if the subtree shrank.
  966. *
  967. * Description:    Recursive routine to delete the smallest node from an
  968. *                AVL tree.
  969. *
  970. ****************************************************************************/
  971. {
  972.     AVL_BUCKET    *p = *pp;
  973.  
  974.     if (p->left)
  975.         return delmin(&p->left) ? balance_left(pp) : 0;
  976.     else {
  977.         *pp = p->right;        /* Delete the node        */
  978.         Node = p;
  979.         return true;        /* Subtree just shrank    */
  980.         }
  981. }
  982.  
  983. PUBLIC void *avl_delmin(AVL_TREE *tree)
  984. /****************************************************************************
  985. *
  986. * Function:        avl_delmin
  987. * Parameters:    tree    - Tree to delete node from
  988. * Returns:        Pointer to the node found, or NULL on error.
  989. *
  990. * Description:    Deletes (removes) the smallest node from an AVL tree. The
  991. *                tree is rebalanced if need be. Note that the node is not
  992. *                freed. You will need to call avl_freenode() to do this.
  993. *
  994. ****************************************************************************/
  995. {
  996.     Node = NULL;
  997.     delmin(&tree->root);
  998.     if (Node)    tree->count--;
  999.     return Node ? AVL_USERSPACE(Node) : NULL;
  1000. }
  1001.  
  1002. /*-------------------------------------------------------------------------*/
  1003.  
  1004. int delmax(AVL_BUCKET **pp)
  1005. /****************************************************************************
  1006. *
  1007. * Function:        delmax
  1008. * Parameters:    root    - Root of subtree to delete from
  1009. * Returns:        True if the subtree shrank.
  1010. *
  1011. * Description:    Recursive routine to delete the largest node from an
  1012. *                AVL tree.
  1013. *
  1014. ****************************************************************************/
  1015. {
  1016.     AVL_BUCKET    *p = *pp;
  1017.  
  1018.     if (p->right)
  1019.         return delmax(&p->right) ? balance_right(pp) : 0;
  1020.     else {
  1021.         *pp = p->left;        /* Delete the node        */
  1022.         Node = p;
  1023.         return true;        /* Subtree just shrank    */
  1024.         }
  1025. }
  1026.  
  1027. PUBLIC void *avl_delmax(AVL_TREE *tree)
  1028. /****************************************************************************
  1029. *
  1030. * Function:        avl_delmax
  1031. * Parameters:    tree    - Tree to delete node from
  1032. * Returns:        Pointer to the node found, or NULL on error.
  1033. *
  1034. * Description:    Deletes (removes) the largest node from an AVL tree. The
  1035. *                tree is rebalanced if need be. Note that the node is not
  1036. *                freed. You will need to call avl_freenode() to do this.
  1037. *
  1038. ****************************************************************************/
  1039. {
  1040.     Node = NULL;
  1041.     delmax(&tree->root);
  1042.     if (Node)    tree->count--;
  1043.     return Node ? AVL_USERSPACE(Node) : NULL;
  1044. }
  1045.  
  1046. /*-------------------------------------------------------------------------*/
  1047.  
  1048.