//====================================================================
// PURPOSE: Template-based AVL Tree Package
// LANGUAGE: C++
// COMPILER: g++ for IBM RS6000 PowerStations
// AUTHOR: Henry D. Shapiro, shapiro@cs.unm.edu
// ADDRESS: Department of Computer Science,
//          The University of New Mexico
//          Albuquerque, NM 87131
//====================================================================

#ifndef AVL_H
#define AVL_H

// <class K> must provide a copy constructor, a destructor, operator<,
//   operator>, and operator<< (used only in routine Print).
// <class D> must provide a copy constructor, operator=, a destructor, and
//   operator<< (used only in routine Print).

#include <iostream>
using namespace std;

template <class K, class D> // class of key/data being stored in tree
class AVL {
public:
    AVL();                            // Create an empty tree.
    AVL(const AVL<K,D>&);             // Perform a deep copy.
    AVL<K,D>& operator=(const AVL<K,D>&);
    ~AVL();

    D* Find(const K&);                // Return a pointer to the data field
                                      //   of the tree_node containing the key
                                      //   or nil, if the key is not in the
                                      //   tree.  The user should be aware that
                                      //   if this key is subsequently deleted,
                                      //   the pointer returned will no longer
                                      //   be valid.
    bool Insert(const K&, const D&);  // Insert a key into the tree.  Return
                                      //   true if the insertion was successful
                                      //   (key was added to the tree) or false
                                      //   if the key was already present (the
                                      //   data will be modified, so this
                                      //   operation can act as an Update).
    bool Delete(const K&);            // Delete a key.  Return true if the
                                      //   key was present (and now no longer
                                      //   is) or false, if the key was not
                                      //   present in the first place.

    // Define an iterator over the tree, using a call-back function.
    //   The function can access the key field (but not change it).  The
    //   function can change the data field.  The return value of f()
    //   is used to terminate the iteration prematurely (true means continue
    //   iteration).
    void Iterate( bool (*f)(const K&, D&) );

    // Special debug routine that checks whether an AVL tree is valid.
    //   This would be eliminated from a working package.
    //   It checks
    //     1. That an in-order search sees the keys in alphabetical order.
    //     2. That there are no repeated keys.
    //     3. That the height difference rules are not violated.
    //     4. That the / = \ indicators match the heights.
    //   Check does not check that the data structure forms a tree (does not
    //     wrap back on itself).  Results are unpredictable in this case, but
    //     should not return that the tree is valid -- infinite looping is
    //     possible.
    //   Check returns silently if the tree is valid.  If it spots that the
    //     tree is invalid it prints the tree (if it is sufficiently small)
    //     and terminates the program.
    //   Note: Check takes linear time, so should be called sparingly.
    void Check() const;

    // Prints out the tree (for debugging purposes) in indented form.
    //   If the tree is very large this routine is not particularly useful.
    //   If the tree is not a tree (wraps back on itself) this routine will
    //     go into an infinite loop.
    // friend ostream& operator<<(ostream&, const BST<K,D>&);
    // There is a bug in g++/Unix that causes the above function to fail to
    //   compile.  The linker returns that it cannot find
    //     ostream& operator<<(ostream&, const AVL<int,double>&)
    //   when the package is instantiated with  int  for  K  and  double
    //   for  D .  operator<< works on some other compilers (some running
    //   in non-Linux environments).
    void Print(ostream&) const;

private:
    // Representation

    enum terminate { stop }; // We break the recursion during interate by
                             //   throwing an exception.  This can be handled
                             //   more elegantly in languages like Pascal and
                             //   Ada that allow nested procedures.  It can
                             //   be handled in C/C++ by a series of rather
                             //   ugly checks in the service function for
                             //   iterate.
                             // The same strategy is used in Check()/check().

    // Used to mark a node as / = or \ leaning.  Left and Right also
    //   used to indicate the direction of travel from a parent to a
    //   child node.  Note: the values assigned to Left, Equal and
    //   Right are carefully chosen so that the code in Insert and Delete
    //   can be (slightly) simplified.
    enum balance { Left = -1, Equal = 0, Right = +1 };

    // Record the downward path during Insert and Delete so that we can
    //   do the rebalancing walk back up toward the root.  MAX_DEPTH set
    //   so high that no tree could possible overrun the length of the
    //   array, so we do not bother to check for array out of bounds
    //   during assignments.  Note: path[i] is the i'th node on the path
    //   from the root to the node inserted/deleted.  path[0] is, therefore,
    //   the root of the tree.  dirOfChildren[i] is the direction of
    //   traversal in going from the node in path[i] to the node in path[i+1].
    //   That is, the direction in which we leave the node at path[i].
    // There are language/compiler related problems with assigning a
    //   value to MAX_DEPTH and allocating path[].  The line
    //   const int MAX_DEPTH = 100   does not compile, but we can fool the
    //   compiler with this enum definition.
    enum { MAX_DEPTH = 100 };
    class tree_node;
    static tree_node* path[MAX_DEPTH];
    static balance /* Left or Right */ dirOfChildren[MAX_DEPTH];

    class tree_node {
    public:
        tree_node(const K& k, const D& d,
              balance LorR, tree_node* l, tree_node* r)
            : key(k), data(d), dir(LorR), left(l), right(r) { }
        ~tree_node() { }; // ... but destructor for classes K and D called

        // Helper functions for various user-visible routines in class AVL.
        static tree_node* copy(const tree_node*); // for copy constructor
        static void destroy(tree_node*);          // for destructor
        static void iterate(tree_node*, bool (*)(const K&, D&));
        static int check(const tree_node*,
                         const K*& smallest, const K*& largest);
          // For a pointer to a nonempty AVL (sub)tree, confirm that
          //   it is a legal AVL (sub)tree and return pointers
          //   to the smallest and largest keys in the (sub)tree,
          //   along with the height of the tree.
        static void print(ostream&, const tree_node*, int indent);
        static int size(const tree_node*);        // size of tree

        K key;
        D data;
        balance dir; // Is the node balanced / = or \.
        tree_node* left;
        tree_node* right;
    };

    tree_node* root;
};

#include "avl.template"
#endif
