home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / lang / c / 11801 < prev    next >
Encoding:
Text File  |  1992-07-30  |  29.7 KB  |  1,060 lines

  1. Newsgroups: comp.lang.c
  2. Path: sparky!uunet!wupost!darwin.sura.net!convex!constellation!munnari.oz.au!bruce.cs.monash.edu.au!monu6!giaeb!s1110238
  3. From: s1110238@giaeb.cc.monash.edu.au (Lee Hollingworth)
  4. Subject: Re: AVL Source Code
  5. Message-ID: <s1110238.712499844@giaeb>
  6. Keywords: If you asked for AVL code read this!
  7. Sender: news@monu6.cc.monash.edu.au (Usenet system)
  8. Organization: Monash University, Melb., Australia.
  9. Date: Thu, 30 Jul 1992 12:37:24 GMT
  10. Lines: 1048
  11.  
  12. Sorry for using the net to post this but my e-mail responce to a few of
  13. the requests for AVL source bounced.
  14.  
  15. So if you DO NOT want a copy of AVL tree code press 'n' now...
  16.  
  17. Lee Hollingworth
  18. s1110238@giaeb.cc.monash.edu.au
  19.  
  20.  
  21. # This is a shell archive.  Remove anything before this line,
  22. # then unpack it by saving it in a file and typing "sh file".
  23. #
  24. # Wrapped by Lee Hollingworth <s1110238@giaeb> on Thu Jul 30 22:17:37 1992
  25. #
  26. # This archive contains:
  27. #    avltree.c    avltree.doc    avltree.h    menu.c        
  28. #    mscmake        tccmake        unixmake    
  29. #
  30.  
  31. LANG=""; export LANG
  32. PATH=/bin:/usr/bin:$PATH; export PATH
  33.  
  34. echo x - avltree.c
  35. cat >avltree.c <<'@EOF'
  36. /*
  37.  * Name:    avltree
  38.  * Purpose: To maintain a balanced binary tree using AVL algorithms
  39.  * Files:   avltree.c  avltree.h
  40.  * Author:  Lee Hollingworth
  41.  * System:  ANSI C comformant
  42.  * Date:    March 4 1992
  43.  */
  44.  
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47.  
  48. #include "avltree.h"
  49.  
  50. /*
  51.  * Name:    rotate_left
  52.  * Purpose: To re-arrange node pointers resulting in a LL rotation
  53.  * Passed:  tree:   address of pointer the rotation root
  54.  * Returns: tree:   pointer to new root node
  55.  */
  56. void rotate_left(trees *tree)
  57. {
  58.     trees left = (*tree)->left;         /* left hand child */
  59.  
  60.     (*tree)->left = left->right;        /* re-arrange pointers */
  61.     left->right = *tree;
  62.     *tree = left;                   /* change root to top node of rotation */
  63. }
  64.  
  65. /*
  66.  * Name:    rotate_right
  67.  * Purpose: To re-arrange node pointers resulting in a RR rotation
  68.  * Passed:  tree:   address of pointer to the rotation node
  69.  * Returns: tree:   pointer to new root node
  70.  */
  71. void rotate_right(trees *tree)
  72. {
  73.     trees right = (*tree)->right;       /* right hand child */
  74.  
  75.     (*tree)->right = right->left;       /* re-arrange pointers */
  76.     right->left = *tree;
  77.     *tree = right;                  /* change root to top node of rotation */
  78. }
  79.  
  80. /*
  81.  * Name:    rot_left_balance
  82.  * Purpose: Balance the root node and it's right child after a LL rotation
  83.  * Passed:  tree:   pointer to root node of rotation after the rotation has
  84.  *                   taken place
  85.  */
  86. void rot_left_balance(trees tree)
  87. {
  88.     tree->balance = EVEN;
  89.     if ((tree->right->left && tree->right->right) ||
  90.             (!tree->right->left && !tree->right->right)) {
  91.         tree->right->balance = EVEN;
  92.     }
  93.     else {
  94.         tree->right->balance = tree->right->right ? R_HEAVY : L_HEAVY;
  95.     }
  96. }
  97.  
  98. /*
  99.  * Name:    rot_right_balance
  100.  * Purpose: Balance the root node and it's left child after a RR rotation
  101.  * Passed:  tree:   pointer to root node of rotation after the rotation has
  102.  *                   taken place
  103.  */
  104. void rot_right_balance(trees tree)
  105. {
  106.     tree->balance = EVEN;
  107.     if ((tree->left->left && tree->left->right) ||
  108.             (!tree->left->left && !tree->left->right)) {
  109.         tree->left->balance = EVEN;
  110.     }
  111.     else {
  112.         tree->left->balance = tree->left->right ? R_HEAVY : L_HEAVY;
  113.     }
  114. }
  115.  
  116. /*
  117.  * Name:    left_balance
  118.  * Purpose: Take care of left rotations, either LL or LR after a node has
  119.  *           been inserted
  120.  * Passed:  tree:   pointer to pointer to root of rotation point which has
  121.  *                   violated the tree balance prior to any rotation taking
  122.  *                   place
  123.  *          key:    the new insertion value
  124.  * Returns: tree:   new root node
  125.  */
  126. void left_balance(trees *tree, keys key)
  127. {
  128.     trees *child = &(*tree)->left;
  129.  
  130.     if (compare((*tree)->left->key,  key) > 0) {  /* LL rotation */
  131.         rotate_left(tree);
  132.         rot_left_balance(*tree);
  133.     }
  134.     else {                                  /* LR rotation */
  135.         rotate_right(child);
  136.         rot_right_balance(*child);
  137.         rotate_left(tree);
  138.         rot_left_balance(*tree);
  139.     }
  140. }
  141.  
  142. /*
  143.  * Name:    right_balance
  144.  * Purpose: Take care of right rotations, either RR or RL after a node has
  145.  *           been inserted
  146.  * Passed:  tree:   pointer to pointer to root of rotation point which has
  147.  *                   violated the tree balance prior to any rotation taking
  148.  *                   place
  149.  *          key:    the new insertion value
  150.  * Returns: tree:   new root node
  151.  */
  152. void right_balance(trees *tree, keys key)
  153. {
  154.     trees *child = &(*tree)->right;
  155.  
  156.     if (compare((*tree)->right->key, key) < 0) {   /* RR rotation */
  157.         rotate_right(tree);
  158.         rot_right_balance(*tree);
  159.     }
  160.     else {                                  /* RL rotation */
  161.         rotate_left(child);
  162.         rot_left_balance(*child);
  163.         rotate_right(tree);
  164.         rot_right_balance(*tree);
  165.     }
  166. }
  167.  
  168. /*
  169.  * Name:    insert
  170.  * Purpose: To search for and insert if necessary a key in a
  171.  *           binary search tree.
  172.  * Passed:  new_key: the key to be inserted
  173.  *          tree:    the tree
  174.  * Returns: tree:    possibly modified tree containing new_key
  175.  *          TRUE     a new node was added so check the balance
  176.  *          FALSE    balance is okay or node already in tree
  177.  *           (maybe should return something else for duplicate key???)
  178.  */
  179. boolean insert(keys new_key, trees *tree)
  180. {
  181.     int result;
  182.  
  183.     if (*tree == NULL) {
  184.         /*
  185.          * at leaf, so key was not in the tree and must be added
  186.          */
  187.         *tree = malloc(sizeof(**tree));
  188.         keycpy((*tree)->key, new_key);
  189.         (*tree)->balance = EVEN;
  190.         (*tree)->left = (*tree)->right = NULL;
  191.         return TRUE;
  192.     }
  193.     else if ((result = compare(new_key, (*tree)->key)) < 0) {
  194.         if (insert(new_key, &((*tree)->left))) {
  195.             switch ((*tree)->balance) {
  196.                 case EVEN:
  197.                     (*tree)->balance = L_HEAVY;
  198.                     return TRUE;
  199.  
  200.                 case R_HEAVY:
  201.                     (*tree)->balance = EVEN;
  202.                     return FALSE;                   /* tree is balanced */
  203.  
  204.                 case L_HEAVY:
  205.                     left_balance(tree, new_key);
  206.                     return FALSE;                   /* tree is balanced */
  207.             }
  208.  
  209.         }
  210.         return FALSE;
  211.     }
  212.     else if (result > 0) {
  213.         if (insert(new_key, &((*tree)->right))) {
  214.             switch ((*tree)->balance) {
  215.                 case EVEN:
  216.                     (*tree)->balance = R_HEAVY;
  217.                     return TRUE;
  218.  
  219.                 case L_HEAVY:
  220.                     (*tree)->balance = EVEN;
  221.                     return FALSE;                   /* tree is balanced */
  222.  
  223.                 case R_HEAVY:
  224.                     right_balance(tree, new_key);
  225.                     return FALSE;                   /* tree is balanced */
  226.             }
  227.         }
  228.         return FALSE;
  229.     }
  230.     else {
  231.         /*
  232.          * key already in tree so return FALSE
  233.          */
  234.         return FALSE;
  235.     }
  236. }
  237.  
  238. /*
  239.  * Name:    del_ll
  240.  * Purpose: Balance the tree after a deletion has taken place and a LL
  241.  *           rotation is required
  242.  * Passed:  tree:   pointer to pointer to root rotation node
  243.  * Returns: tree:   pointer to pointer to new root node after rotation
  244.  */
  245. void del_ll(trees *tree)
  246. {
  247.     if ((*tree)->balance == L_HEAVY && (*tree)->left->balance == EVEN) {
  248.         (*tree)->left->balance = R_HEAVY;
  249.     }
  250.     else {
  251.         (*tree)->balance = EVEN;
  252.         (*tree)->left->balance = R_HEAVY;
  253.     }
  254.  
  255.     rotate_left(tree);
  256. }
  257.  
  258. /*
  259.  * Name:    del_rr
  260.  * Purpose: Balance the tree after a deletion has taken place and a RR
  261.  *           rotation is required
  262.  * Passed:  tree:   pointer to pointer to root rotation node
  263.  * Returns: tree:   pointer to pointer to new root node after rotation
  264.  */
  265. void del_rr(trees *tree)
  266. {
  267.     if ((*tree)->balance == R_HEAVY && (*tree)->right->balance == EVEN) {
  268.         (*tree)->right->balance = L_HEAVY;
  269.     }
  270.     else {
  271.         (*tree)->balance = EVEN;
  272.         (*tree)->right->balance = L_HEAVY;
  273.     }
  274.     rotate_right(tree);
  275. }
  276.  
  277. /*
  278.  * Name:    del_lr
  279.  * Purpose: Balance the tree after a deletion has taken place and a LR
  280.  *           rotation is required
  281.  * Passed:  tree:   pointer to pointer to root rotation node
  282.  * Returns: tree:   pointer to pointer to new root node after rotation
  283.  */
  284. void del_lr(trees *tree)
  285. {
  286.     trees *child = &(*tree)->left;
  287.  
  288.     /*
  289.      * (*tree)->balance == L_HEAVY in all cases
  290.      * (*child)->balance == R_HEAVY in all cases
  291.      */
  292.  
  293.     switch ((*child)->right->balance) {
  294.         case R_HEAVY:
  295.             (*child)->balance = L_HEAVY;
  296.             (*child)->right->balance = EVEN;        /* new root */
  297.             (*tree)->balance = EVEN;
  298.             break;
  299.  
  300.         case EVEN:
  301.             (*child)->balance = EVEN;
  302.             (*tree)->balance = EVEN;
  303.             break;
  304.  
  305.         case L_HEAVY:
  306.             (*child)->balance = EVEN;
  307.             (*tree)->balance = R_HEAVY;
  308.             (*child)->right->balance = EVEN;
  309.             break;
  310.     }
  311.  
  312.     rotate_right(child);
  313.     rotate_left(tree);
  314. }
  315.  
  316. /*
  317.  * Name:    del_rl
  318.  * Purpose: Balance the tree after a deletion has taken place and a RL
  319.  *           rotation is required
  320.  * Passed:  tree:   pointer to pointer to root rotation node
  321.  * Returns: tree:   pointer to pointer to new root node after rotation
  322.  */
  323. void del_rl(trees *tree)
  324. {
  325.     trees *child = &(*tree)->right;
  326.  
  327.     /*
  328.      * (*tree)->balance == R_HEAVY in all cases
  329.      * (*child)->balance == L_HEAVY in all cases
  330.      */
  331.  
  332.     switch ((*child)->left->balance) {
  333.         case L_HEAVY:
  334.             (*child)->balance = R_HEAVY;
  335.             (*child)->left->balance = EVEN;         /* new root */
  336.             (*tree)->balance = EVEN;
  337.             break;
  338.  
  339.         case EVEN:
  340.             (*child)->balance = EVEN;
  341.             (*tree)->balance = EVEN;
  342.             break;
  343.  
  344.         case R_HEAVY:
  345.             (*child)->balance = EVEN;
  346.             (*tree)->balance = L_HEAVY;
  347.             (*child)->left->balance = EVEN;
  348.             break;
  349.     }
  350.  
  351.     rotate_left(child);
  352.     rotate_right(tree);
  353. }
  354.  
  355. /*
  356.  * Name:    left_path_balance
  357.  * Purpose: If returning up the left path, check the current nodes balance
  358.  *           and adjust if required
  359.  * Passed:  pointer to pointer to the root node
  360.  * Returns: FALSE no further balancing required above this point
  361.  *          TRUE continue to balance up the tree
  362.  */
  363. boolean left_path_balance(trees *tree)
  364. {
  365.     switch ((*tree)->balance) {
  366.         case EVEN:          /* no further balancing req'd */
  367.             (*tree)->balance = R_HEAVY;
  368.             return FALSE;
  369.  
  370.         case L_HEAVY:       /* check further up... */
  371.             (*tree)->balance = EVEN;
  372.             break;
  373.  
  374.         case R_HEAVY:       /* tree is unbalanced rotations req'd */
  375.             /*
  376.              * three possible cases now exist
  377.              * 1. right child is EVEN
  378.              * 2. right child is R_HEAVY
  379.              * 3. right child is L_HEAVY
  380.              * 1 = RR and change balances according to current
  381.              *      balances, tree is now balanced
  382.              * 2 = set both balances to EVEN and RR
  383.              * 3 = RL and change balances according to current
  384.              *      balances
  385.              */
  386.             switch ((*tree)->right->balance) {
  387.                 case EVEN:
  388.                     del_rr(tree);
  389.                     return FALSE;
  390.  
  391.                 case R_HEAVY:
  392.                     (*tree)->balance = EVEN;
  393.                     (*tree)->right->balance = EVEN;
  394.                     rotate_right(tree);
  395.                     break;
  396.  
  397.                 case L_HEAVY:
  398.                     del_rl(tree);
  399.                     break;
  400.             }
  401.     }
  402.     return TRUE;
  403. }
  404.  
  405. /*
  406.  * Name:    right_path_balance
  407.  * Purpose: If returning up the right path, check the current nodes balance
  408.  *           and adjust if required
  409.  * Passed:  pointer to pointer to the root node
  410.  * Returns: FALSE no further balancing required above this point
  411.  *          TRUE continue to balance up the tree
  412.  */
  413. boolean right_path_balance(trees *tree)
  414. {
  415.     switch ((*tree)->balance) {
  416.         case EVEN:      /* no further balancing req'd */
  417.             (*tree)->balance = L_HEAVY;
  418.             return FALSE;
  419.  
  420.         case R_HEAVY:   /* continue to check on the way up */
  421.             (*tree)->balance = EVEN;
  422.             break;
  423.  
  424.         case L_HEAVY:
  425.             /*
  426.              * three possible cases now exist
  427.              * 1. left child is EVEN
  428.              * 2. left child is L_HEAVY
  429.              * 3. left child is R_HEAVY
  430.              * 1 = LL and change balances according to current
  431.              *      balances, tree is now balanced
  432.              * 2 = set both balances to EVEN and LL
  433.              * 3 = LR and change balances according to current
  434.              *      balances
  435.              */
  436.             switch ((*tree)->left->balance) {
  437.                 case EVEN:
  438.                     del_ll(tree);
  439.                     return FALSE;
  440.  
  441.                 case L_HEAVY:
  442.                     (*tree)->balance = EVEN;
  443.                     (*tree)->left->balance = EVEN;
  444.                     rotate_left(tree);
  445.                     break;
  446.  
  447.                 case R_HEAVY:
  448.                     del_lr(tree);
  449.                     break;
  450.             }
  451.     }
  452.     return TRUE;
  453. }
  454.  
  455. /*
  456.  * Name:    left_most
  457.  * Purpose: To retrieve the left most descendent of the tree,
  458.  *            and delete this leaf node.
  459.  * Passed:  tree: the tree to be searched
  460.  * Returns: key:     the left most key in this tree
  461.  *          tree:    the tree minus the leftmost node
  462.  *          TRUE until point of balance is reached
  463.  *          FALSE if no deletion or balance acheived
  464.  */
  465. boolean left_most(trees *tree, keys *key)
  466. {
  467.     trees p;               /* node to be disposed of */
  468.  
  469.     /*
  470.      * first make sure there is something there to find
  471.      */
  472.     if ((*tree) != NULL) {
  473.         /*
  474.          * see if we are already at the bottom of the tree
  475.          */
  476.         if ((*tree)->left == NULL) {
  477.             /*
  478.              * return this left most node, and delete it, tree path is now
  479.              * shorter so return TRUE
  480.              */
  481.             *key = (*tree)->key;
  482.             p = (*tree);
  483.             (*tree) = (*tree)->right;
  484.             free(p);
  485.             return TRUE;
  486.         }
  487.         else {
  488.             /*
  489.              * recurse down the left sub-tree, return of TRUE means a node
  490.              * was removed from the left path so check balance of tree on
  491.              * way up and adjust accordingly
  492.              */
  493.             if (left_most(&((*tree)->left), key)) {
  494.                 return left_path_balance(tree);
  495.             }
  496.             return FALSE;
  497.         }
  498.     }
  499.     return FALSE;
  500. }
  501.  
  502. /*
  503.  * Name:    del_item
  504.  * Purpose: To delete the item in the root of the tree.
  505.  * Passed:  tree:    the tree whose root must be deleted
  506.  * Returns: tree:    the tree with its root deleted
  507.  *          TRUE until point of balance is reached
  508.  *          FALSE if no deletion or balance acheived
  509.  */
  510. boolean del_item(trees *tree)
  511. {
  512.     trees p;                /* node to be disposed of */
  513.  
  514.     /*
  515.      * first check that there is something to de deleted
  516.      */
  517.     if ((*tree) != NULL) {
  518.         if (((*tree)->left == NULL) && ((*tree)->right == NULL)) {
  519.             /*
  520.              * if tree is a leaf, then it can be deleted easily, path
  521.              *  has been shortened so return TRUE
  522.              */
  523.             free((*tree));
  524.             (*tree) = NULL;
  525.             return TRUE;
  526.         }
  527.         else if ((*tree)->left == NULL) {
  528.             /*
  529.              * if the tree only has a right child, then the root
  530.              *  can be replaced by the right child
  531.              * path has been shortened so return TRUE
  532.              */
  533.             p = (*tree);
  534.             (*tree) = (*tree)->right;
  535.             free(p);
  536.             return TRUE;
  537.         }
  538.         else if ((*tree)->right == NULL) {
  539.             /*
  540.              * if the tree only has a left child, then the root
  541.              *  can be replaced by the left child
  542.              * path has been shortened so return TRUE
  543.              */
  544.             p = (*tree);
  545.             (*tree) = (*tree)->left;
  546.             free(p);
  547.             return TRUE;
  548.         }
  549.         else {
  550.             /*
  551.              * if the tree has two children, then recurse to find
  552.              *  the smallest key larger than the root (i.e. the
  553.              *  left most key to the right of the root)
  554.              * the path from where the replacement node has been
  555.              *  taken is shortened, so the tree must be re-balanced
  556.              *  accordingly
  557.              */
  558.             if (left_most(&((*tree)->right), &(*tree)->key)) {
  559.                 return right_path_balance(tree);
  560.             }
  561.             return FALSE;
  562.         }
  563.     }
  564. }
  565.  
  566. /*
  567.  * Name:    delete
  568.  * Purpose: To delete an item from the tree.
  569.  * Passed:  tree:    the tree to be deleted from
  570.  *          key:     the key value of the item to be deleted
  571.  * Returns: tree:    the tree with the item deleted
  572.  *          TRUE  balancing required
  573.  *          FALSE no further balancing required
  574.  */
  575. boolean delete(trees *tree, keys key)
  576. {
  577.     int result;
  578.  
  579.     if ((*tree) == NULL) {
  580.         /*
  581.          * key not in tree
  582.          */
  583.         return FALSE;
  584.     }
  585.     else if ((result = compare(key, (*tree)->key)) == 0) {
  586.         /*
  587.          * key found
  588.          */
  589.         return del_item(tree);
  590.     }
  591.     else if (result < 0) {
  592.         /*
  593.          * key could be in left sub-tree
  594.          */
  595.         if (delete(&((*tree)->left), key)) {
  596.             return left_path_balance(tree);
  597.         }
  598.         return FALSE;
  599.     }
  600.     else {
  601.         /*
  602.          * key could be in right sub-tree
  603.          */
  604.         if (delete(&((*tree)->right), key)) {
  605.             return right_path_balance(tree);
  606.         }
  607.         return FALSE;
  608.     }
  609. }
  610.  
  611. /*
  612.  * Name:    find
  613.  * Purpose: To search for a key in the binary search tree.
  614.  * Passed:  key: the key to be found
  615.  *          tree:    the tree
  616.  * Returns: TRUE     the node was found
  617.  *          FALSE    the node was not found
  618.  */
  619. boolean find(keys key, trees tree)
  620. {
  621.     int result;
  622.  
  623.     if (tree == NULL) {
  624.         /*
  625.          * at leaf, so key was not in the tree
  626.          */
  627.         return FALSE;
  628.     }
  629.     else if ((result = compare(key, tree->key)) < 0) {
  630.         return (find(key, tree->left));
  631.     }
  632.     else if (result > 0) {
  633.         return (find(key, tree->right));
  634.     }
  635.     else {
  636.         /*
  637.          * key found
  638.          */
  639.         return TRUE;
  640.     }
  641. }
  642. @EOF
  643.  
  644. chmod 600 avltree.c
  645.  
  646. echo x - avltree.doc
  647. cat >avltree.doc <<'@EOF'
  648. AVLtree.doc -- AVL tree deletion                            Lee Hollingworth
  649.  
  650. The deletion of a node from an AVL balanced tree is far more complex than an
  651. insertion, as can easily be confirmed by the way in which any text I could
  652. find "left the implementation as an exercise to the reader"!
  653.  
  654. The problem of deletion can be reduced to the following steps:
  655.  
  656.     1. Reduce the problem to the point where the node to be deleted, say
  657.        'p' has at most one child.  This of course was taken care of for
  658.        us with the code supplied by me.  The code supplied uses the
  659.        an in-order traversal to find the successor of p.
  660.        For the rest of this explanation this child will be called 'q'.
  661.  
  662.     2. Delete the node 'q' from the tree.  As my comments state, it is
  663.        known that 'q' can only have a right child by virtue of the method
  664.        used to find it.  So deletion is a simple matter of linking the
  665.        parent of 'q' to it's right child, which of course could be NULL.
  666.        The height of the path from 'p' to 'q' has  now been reduced by 1,
  667.        and the effects of this change in height must be traced back up the
  668.        path from 'q' to the root of the tree.
  669.        A boolean value of either TRUE or FALSE is used to show if the height
  670.        of the current sub-tree has been shortened.  Using this value and
  671.        the current node's balance and it's child's balance we can take the
  672.        necessary action required in balancing the tree.
  673.  
  674.     3. Using the initial return value of TRUE, the following steps are
  675.        undertaken, based upon the current value of each node 's' and the
  676.        *return* path traveled to get to 's'.
  677.        By returning FALSE the tree above that point remains unchanged.
  678.  
  679.     4. i.   The balance factor of 's' is EQUAL.  The balance factor of 's'
  680.             is changed in accordance with whether the left or right path
  681.             was shortened and the boolean value FALSE is passed on up the tree,
  682.             thus terminating the need for any further changes.
  683.  
  684.        ii.  The balance of 's' is not EQUAL, but the taller sub-tree was
  685.             shortened.  Change the balance of 's' to EQUAL and return TRUE.
  686.  
  687.        iii. The balance of 's' is not EQUAL, but the shorter sub-tree was
  688.             shortened.
  689.             This is a point in which a leaf in the sub-tree is 2 levels
  690.             taller than it's matching leaf, thus violating AVL balance.
  691.             Now a rotation is required to restore balance, but the rotation
  692.             required depends upon the balance value of 's' and it's child on
  693.             the taller sub-tree 't' (the path not shortened).
  694.  
  695.             a.  The balance value of 't' is EQUAL.  A single rotation is
  696.                 required, with appropriate balance changes (easily said),
  697.                 and FALSE is returned up the tree.
  698.  
  699.             b.  The balance value of 't' is the same as 's'. A single rotation
  700.                 is required, set 't' and 's' to EQUAL and return TRUE.
  701.  
  702.             c.  The balance of 's' and 't' are opposite.  A double rotation,
  703.                 first around 't' and then 's' is required, set the balance
  704.                 factor of the new root to EQUAL and the other as appropriate
  705.                 (very easily said).  Return TRUE.
  706.  
  707.        As usual the rotations required in 4(iii) depends upon which sub-tree
  708.        was shortened, basically the opposite to an insertion.
  709.  
  710. The above is basically paraphrased from the book _Data Structures and Program
  711. Design in C_  by Kruse, Leung and Tondo, Prentice Hall page 338.
  712.  
  713. Unfortunately they do not give a coded example!
  714.  
  715. The obvious problem with AVL tree node deletion is that of ensuring the correct
  716. balance values is maintained within each node in the path from replacement node
  717. to root.
  718. To assist in this matter I have included a defined constant called SHOW_BALANCE
  719. which if included at compile time will result in each node showing it's balance
  720. value when printed.  This constant can be commented out to produce a normal
  721. printed tree.
  722.  
  723. @EOF
  724.  
  725. chmod 600 avltree.doc
  726.  
  727. echo x - avltree.h
  728. cat >avltree.h <<'@EOF'
  729. /*
  730.  * Name    : avltree
  731.  * Purpose : Header file for avltree.c
  732.  * Author  : Lee Hollingworth
  733.  */
  734.  
  735. /*
  736.  * macro   : compare
  737.  * purpose : simple compare macro which is implemented here so that if the key
  738.  *           field in the node structure is changed, the only place the code
  739.  *           needs to be changed is here...
  740.  * returns :  0 - a and b are equal
  741.  *            1 - a is greater than b
  742.  *           -1 - b is greater than a
  743.  *
  744.  * note compatible with strcmp
  745.  */
  746. #define compare(a, b)  (a) == (b) ? 0 : (a) > (b) ? 1 : -1
  747.  
  748. /*
  749.  * macro   : keycpy
  750.  * purpose : copy one key into another
  751.  * note    : can be replaced by any copy function such as strcpy for string
  752.  *           keys
  753.  */
  754. #define keycpy(a, b) a = b
  755.  
  756. /*
  757.  * datatype: balances
  758.  * purpose : mainatin a balance field in the current node
  759.  */
  760. typedef enum {EVEN, L_HEAVY, R_HEAVY} balances;
  761.  
  762. /*
  763.  * datatype: boolean
  764.  * purpose : TRUE - FALSE data type
  765.  */
  766. typedef enum {FALSE, TRUE} boolean;
  767.  
  768. /*
  769.  * datatype: keys
  770.  * purpose : define a key field data type
  771.  */
  772. typedef int keys;
  773.  
  774. /*
  775.  * datatype: node
  776.  * purpose : tree node structure
  777.  */
  778. typedef struct node {
  779.     keys key;                   /* search key */
  780.     balances balance;           /* level of balance of children */
  781.     struct node *left;          /* left sub-tree */
  782.     struct node *right;         /* right sub-tree */
  783. };
  784.  
  785. /*
  786.  * datatype: nodes
  787.  * purpose : define node type
  788.  */
  789. typedef struct node *trees;     /* every tree or sub-tree */
  790.  
  791. /*
  792.  * functions "interfaced" to other source code
  793.  */
  794. boolean  insert(keys new_key,trees *tree);      /* insert new node */
  795. boolean  delete(trees *tree,keys key);          /* delete a node */
  796. boolean  find(keys key, trees tree);            /* find a node */
  797.  
  798. /*
  799.  * functions "private" to avltree.c
  800.  */
  801. void  rotate_left(trees *tree);
  802. void  rotate_right(trees *tree);
  803. void  rot_left_balance(trees tree);
  804. void  rot_right_balance(trees tree);
  805. void  left_balance(trees *tree, keys key);
  806. void  right_balance(trees *tree, keys key);
  807. void  del_ll(trees *tree);
  808. void  del_rr(trees *tree);
  809. void  del_lr(trees *tree);
  810. void  del_rl(trees *tree);
  811. boolean  left_path_balance(trees *tree);
  812. boolean  right_path_balance(trees *tree);
  813. boolean  left_most(trees *tree, keys *key);
  814. boolean  del_item(trees *tree);
  815. @EOF
  816.  
  817. chmod 600 avltree.h
  818.  
  819. echo x - menu.c
  820. cat >menu.c <<'@EOF'
  821. /*
  822.  * Name:    Balanced binary search with AVL balancing
  823.  * Purpose: To insert and delete keys into a binary tree and display the
  824.  *           result using AVL algorithms to maintain a balanced tree.
  825.  * File:    avltree.c
  826.  * Author:  Lee Hollingworth
  827.  * System:  ANSI C comformant
  828.  * Date:    March 4 1992
  829.  */
  830.  
  831. #include <stdio.h>
  832. #include <stdlib.h>
  833.  
  834. #include "avltree.h"
  835.  
  836. /*
  837.  * SHOW_BALANCE allows the tree node balances to be shown for easy viewing
  838.  *  of tree re-balancing after deletions or insertions
  839.  *  to use it just remove comments markers
  840.  */
  841.  
  842.  
  843. #define SHOW_BALANCE
  844.  
  845.  
  846. typedef enum {ADD, DELETE, FIND, QUIT} options;
  847.  
  848. /*
  849.  * Name:    print_tree
  850.  * Purpose: To display the entire tree in a reasonable format.
  851.  * Passed:  tree:  the tree to be displayed
  852.  *          level: how far down from the root of the tree we are
  853.  * Output:  visual representation of the tree
  854.  */
  855. void print_tree(trees tree, int level)
  856. {
  857.     int i;
  858.  
  859.     /*
  860.      * recursion ceases when we reach the bottom of the tree
  861.      */
  862.     if (tree != NULL) {
  863.        /*
  864.         * Still more tree to print, so print the right sub-tree,
  865.         *  then this node, then the left sub-tree.
  866.         * Indentation is proportional to the depth in the tree.
  867.         */
  868.         print_tree(tree->right, level+1);
  869.         for (i=0; i < level; i++)
  870.             printf("       ");
  871.         printf("%d", tree->key);
  872.  
  873.         #ifdef SHOW_BALANCE
  874.         printf("%c", tree->balance == 0 ? 'E' : tree->balance == 1 ? 'L' : 'R');
  875.         #endif
  876.  
  877.         printf("\n");
  878.         print_tree(tree->left, level+1);
  879.     }
  880. }
  881.  
  882. /*
  883.  * Name:    menu
  884.  * Purpose: To display a menu and input the user's selection.
  885.  * Returns: selection
  886.  */
  887. int menu(void)
  888. {
  889.     int c;
  890.  
  891.     for (;;) {
  892.         printf("Add, Delete, Find or Quit? (a/d/f/q): ");
  893.         while ((c = tolower(getchar())) == '\n')
  894.             ;
  895.         switch (c) {
  896.         case 'a':
  897.             return ADD;
  898.         case 'd':
  899.             return DELETE;
  900.         case 'f':
  901.             return FIND;
  902.         case 'q':
  903.             return QUIT;
  904.         }
  905.     }
  906. }
  907.  
  908. /*
  909.  * Name:    main
  910.  * Purpose: See comments at start of program.
  911.  */
  912. void main(void)
  913. {
  914.     trees root;                 /* the entire tree */
  915.     keys key;                   /* the key being added */
  916.  
  917.     root = NULL;   /* start with an empty tree */
  918.  
  919.     /*
  920.      * Keep on inputting a new key, adding or deleting this key,
  921.      *  and displaying the resultant tree, until the user wants
  922.      *  to stop.
  923.      */
  924.     for (;;) {
  925.         switch (menu()) {
  926.         case ADD:
  927.             printf("Key to add: ");
  928.             scanf("%d", &key);
  929.             insert(key, &root);
  930.             break;
  931.         case DELETE:
  932.             printf("Key to delete: ");
  933.             scanf("%d", &key);
  934.             delete(&root, key);
  935.             break;
  936.         case FIND:
  937.             printf("Key to find: ");
  938.             scanf("%d", &key);
  939.             if (find(key, root)) {
  940.                 printf("%d: Key found!\n", key);
  941.             }
  942.             else {
  943.                 printf("%d: Key not in tree...\n", key);
  944.             }
  945.             break;
  946.         case QUIT:
  947.             exit(0);
  948.         }
  949.         print_tree(root, 0);
  950.     }
  951. }
  952. @EOF
  953.  
  954. chmod 600 menu.c
  955.  
  956.  
  957. rm -f /tmp/uud$$
  958. (echo "begin 666 /tmp/uud$$\n#;VL*n#6%@x\n \nend" | uudecode) >/dev/null 2>&1
  959. if [ X"`cat /tmp/uud$$ 2>&1`" = Xok ]
  960. then
  961.     unpacker=uudecode
  962. else
  963.     echo Compiling unpacker for non-ascii files
  964.     pwd=`pwd`; cd /tmp
  965.     cat >unpack$$.c <<'EOF'
  966. #include <stdio.h>
  967. #define C (*p++ - ' ' & 077)
  968. main()
  969. {
  970.     int n;
  971.     char buf[128], *p, a,b;
  972.  
  973.     scanf("begin %o ", &n);
  974.     gets(buf);
  975.  
  976.     if (freopen(buf, "w", stdout) == NULL) {
  977.         perror(buf);
  978.         exit(1);
  979.     }
  980.  
  981.     while (gets(p=buf) && (n=C)) {
  982.         while (n>0) {
  983.             a = C;
  984.             if (n-- > 0) putchar(a << 2 | (b=C) >> 4);
  985.             if (n-- > 0) putchar(b << 4 | (a=C) >> 2);
  986.             if (n-- > 0) putchar(a << 6 | C);
  987.         }
  988.     }
  989.     exit(0);
  990. }
  991. EOF
  992.     cc -o unpack$$ unpack$$.c
  993.     rm unpack$$.c
  994.     cd $pwd
  995.     unpacker=/tmp/unpack$$
  996. fi
  997. rm -f /tmp/uud$$
  998.  
  999. echo x - mscmake '[non-ascii]'
  1000. $unpacker <<'@eof'
  1001. begin 600 mscmake
  1002. M(R!-86ME($%63"Y%6$4@=&\@<G5N(&]N(&UO<W0@24)-(%!#('-Y<W1E;7,NX
  1003. M"B,@5&AI<R!F:6QE(&ES(&9O<B!-:6-R;W-O9G0@0R V+C @;W(@475I8VL@X
  1004. M0R R+C4Q"B,@268@=7-I;F<@34%+12 H;F]T($Y-04M%*2!C;VUM96YT(&]UX
  1005. M="!N97AT(&QI;F4N"D%,3" Z(&%V;"YE>&4*"BYC+F]B:CH*(" @(&-L("]CX
  1006. M("]!4R O5S0@+T<R("]*("0\"@IM96YU+F]B:CH@879L=')E92YH(&UE;G4NX
  1007. M8PIA=FQT<F5E+F]B:CH@879L=')E92YH(&%V;'1R964N8PH*879L+F5X93H@X
  1008. M;65N=2YO8FH@879L=')E92YO8FH*(" @3$E.2R!M96YU(&%V;'1R964L(&%VX
  1009. *;"YE>&4["B @('9L                                            X
  1010.                                                              X
  1011. end
  1012. @eof
  1013.  
  1014. chmod 600 mscmake
  1015.  
  1016. echo x - tccmake
  1017. sed 's/^@//' >tccmake <<'@EOF'
  1018. #    Turbo C++ Make file for AVL tree program.
  1019.  
  1020. #    Implicit rules.
  1021.  
  1022. @.c.obj:
  1023.     tcc -c $<
  1024.  
  1025. #    Targets.
  1026.  
  1027. avl.exe:        menu.obj avltree.obj
  1028.         tcc -G -O -Z -w -eavl.exe menu.obj avltree.obj
  1029.  
  1030. #    Dependencies.
  1031.  
  1032. menu.obj:      menu.c avltree.h
  1033. avltree.obj:   avltree.c avltree.h
  1034. @EOF
  1035.  
  1036. chmod 600 tccmake
  1037.  
  1038. echo x - unixmake
  1039. sed 's/^@//' >unixmake <<'@EOF'
  1040. # Make avltree for UNIX [System V] systems
  1041.  
  1042. OBJECTS = menu.o avltree.o
  1043.  
  1044. # -z - check for dereferencing NULL pointer
  1045. CCFLAGS = -O -z +DA1.0
  1046.  
  1047. @.c.o:           ; cc $(CCFLAGS) -c -DUNIX $*.c
  1048.  
  1049. avltree: $(OBJECTS) ; cc $(CCFLAGS) -o avltree $(OBJECTS) -lcurses
  1050.  
  1051. $(OBJECTS):     avltree.h
  1052. menu.o:
  1053. avltree.o:
  1054. @EOF
  1055.  
  1056. chmod 644 unixmake
  1057.  
  1058. rm -f /tmp/unpack$$
  1059. exit 0
  1060.