
/**
 * Title:        Math 176 Homework #1 Programs<p>
 * Description:  Solutions to Homework #1.
 * Math 176, Fall 2000.<p>
 * Copyright:    Copyright (c) Sam Buss<p>
 * Company:      UCSD<p>
 * @author Sam Buss
 * @version 1.0
 */

import java.util.*;

/**
 * An implementation of the <code>AbstractSet</code> interface from
 * <code>java.util</code> based on threaded AVL trees.
 * <p>
 * One advantage of threaded AVL trees is that they support iterators,
 * without needing the extra space for nodes to store references to their
 * parents.  In addition, all operations are guaranteed to take O(log n)
 * time in the worst case.
 * <p>
 * For the first homework assignment in Math 176, you must develop
 * a Threaded AVL Tree implementation which has exactly the four
 * methods shown below.  In addition, you must let it have an
 * INNER CLASS named AvlIterator, which must be declared as
 * <p>
 * <center><code>
 * private class AvlIterator implements Iterator
 * </code></center>
 * <p>
 * This iterator must have the following methods:
 * <p>
 * <code>public boolean hasNext()</code>
 * <br>
 * <code>public Object next()</code>
 * <br>
 * <code>public void remove()</code>
 * <p>
 * See the java documentation for Iterator's to see how these methods
 * should function.    Note that you may implement additional functions
 * if you wish (and this will probably be helpful to you); this is fine as
 * long as you implement at least the functions as above.
 */
public class ThreadedAvlTree extends AbstractSet {

  private ThreadedAvlTree( Object o ) {}

/**
 * Counts the number of modifications.  Needed to make the iterators
 * fail-safe, so they will abort when the AVL tree is modified by another
 * iterator.
 */
  private transient int modCount = 0;

/**
 * Number of elements in the AVL tree.
 */
  private long numElements = 0;

/**
 * Sentinal node above the root of the tree.
 */
  private AvlTreeNode sentinalNode;

/**
 * Root node of the tree;
 */
  private AvlTreeNode rootNode = null;

/**
 * Creates an empty AVL tree.
 */
  public ThreadedAvlTree() {
    // Create a sentinal node above the root.
    sentinalNode = new AvlTreeNode();
    sentinalNode.setChildren( null, null );
    sentinalNode.setHeight( -1 );
  }

/**
 * Creates an iterator for the AVL tree.  It is positioned at the first
 * element and is guarenteed to produce the elements in sorted version.
 * <P>
 * The basic version supports <code>hasNext</code> and <code>next</code>
 * and the full version supports <code>remove</code>.  For Math 176, it
 * is not necessary to make the <code>Iterator</code> <em>fail-safe</em>,
 * but this would be the preferred implementation.
 */
  public Iterator iterator() {
    return new AvlIterator();
  }

/**
 * Get the number of elements in the AVL tree.
 * @return the number of elements.
 */
  public int size() {
    return (int)numElements;  // Shortsighted to allow only int's for size!
  }

/**
 * A temporary variable that indicates whether the <code>addBelow</code>
 * operation was aborted due to finding a duplicate entry.
 */
  private transient boolean isDuplicate;  // Temporary variable

/**
 * Adds the specified element to this set if it is not already present.
 * Also, the object <code>null</code> will not be added to the set.
 * @return <code>true</code> is the object was added to the set,
 *    <code>false</code> if the object was already present in the set.
 * @throws IllegalArgumentException if the object is <code>null</code>
 */
  public boolean add( Object o ) {
    if ( o == null || !(o instanceof Comparable) ) {
      throw new IllegalArgumentException();
    }
    boolean returnCode;
    if ( isEmpty() ) {
      //  Add object as the first object in the tree, as the new root.
      rootNode = new AvlTreeNode((Comparable)o);
      rootNode.setChildren( sentinalNode, sentinalNode );
      sentinalNode.setChildren( rootNode, rootNode );
      returnCode = true;
    }
    else {
      isDuplicate = false;
      rootNode = addBelow( (Comparable)o, rootNode );
      returnCode = !isDuplicate;
    }
    if ( returnCode ) {
      numElements++;
      modCount++;
    }
    return returnCode;
  }

/**
 * A temporary variable that indicates whether the <code>removeBelow</code>
 * operation find the object and removed it.
 */
  private transient boolean isRemoved;  // Temporary variable
  private int tempDebug;
/**
 * Remove an element from the AVL tree.
 * @param o the object to be removed.
 * @return <code>true</code> if the object was removed.  <code>false</code>
 *    if the object was not present in the set.
 */
  public boolean remove ( Object o ) {
    if ( numElements==0 ) {
      return false;
    }
    isRemoved = false;
    tempDebug=0;
    rootNode = removeBelow( (Comparable)o, rootNode );
    if ( isRemoved ) {
      modCount++;
      numElements--;
    }
    return isRemoved;
  }

/**
 * Used recursively to add a new element below an AVL tree node.
 * @param o the object to add.  Must be a <code>Comparable</code>.
 * @param node the root of the subtree under which the object <code>o</code>
 *    is to be added.
 * @return The root of the subtree after the element has been add'ed.
 * Will be just <code>node</code> unless an AVL tree rebalancing occurred
 * at the node.
 */
  private AvlTreeNode addBelow( Comparable o, AvlTreeNode node ) {
    int i = o.compareTo(node.getObject());
    if ( i==0 ) {
      isDuplicate = true;
      return node;      // Equal to the object at this node
    }
    else if ( i<0 ) {
      // in the left subtree
      if ( node.hasLeftChild() ) {
        // add to the left subtree with a recursive call
        AvlTreeNode newSubRoot = addBelow( o, node.leftChild() );
        if ( newSubRoot != node.leftChild() ) {
          node.setLeftChild( newSubRoot );
          return node;                          // No need to rebalance
        }
        if ( node.height()<=node.leftChild.height() ) {
          node.setHeight( node.leftChild.height()+1 );
        }
        int htA = node.getRightChildHeight();
        if ( node.height() > 2+htA ) {
          // The AVL tree property must be restored.
          int htC = node.leftChild().getLeftChildHeight();
          if ( htC > htA ) {
            return( rightRotate( node ) );
          }
          else {
            node.setLeftChild( leftRotate( node.leftChild() ) );
            node.setHeight(1+node.leftChild().height());
            return( rightRotate( node ) );
          }
        }
        else {
          return node;
        }
      }
      else {
        // Add as a left child
        AvlTreeNode newLeaf = new AvlTreeNode(o);
        newLeaf.setLeftChild( node.leftChild() ); // In-order predecessor.
        newLeaf.setRightChild( node );            // In-order successor.
        node.setLeftChild( newLeaf );
        node.setHeight(1);                     // Height must be 1 by AVL property
        if ( sentinalNode.rightChild==node ) {
          sentinalNode.rightChild = newLeaf;       // This is the new first node
        }
        return node;                            // No need to rebalance here
      }

    }
    else {
      // in the right subtree
      if ( node.hasRightChild() ) {
        // add to the right subtree with a recursive call
        AvlTreeNode newSubRoot = addBelow( o, node.rightChild() );
        if ( newSubRoot != node.rightChild() ) {
          node.setRightChild( newSubRoot );
          return node;                          // No need to rebalance
        }
        if ( node.height()<=node.rightChild().height() ) {
          node.setHeight( node.rightChild().height()+1 );
        }
        int htA = node.getLeftChildHeight();
        if ( node.height() > 2+htA ) {
          // The AVL tree property must be restored.
          int htC = node.rightChild().getRightChildHeight();
          if ( htC > htA ) {
            return( leftRotate( node ) );
          }
          else {
            node.setRightChild( rightRotate( node.rightChild() ) );
            node.setHeight(1+node.rightChild().height());
            return( leftRotate( node ) );
          }
        }
        else {
          return node;
        }
      }
      else {      // Add as a right child
        AvlTreeNode newLeaf = new AvlTreeNode(o);
        newLeaf.setLeftChild( node );                 // In-order predecessor.
        newLeaf.setRightChild( node.rightChild() );   // In-order successor.
        node.setRightChild( newLeaf );
        node.setHeight(1);                // Height = 1 by AVL property
        if ( sentinalNode.leftChild==node ) {
          sentinalNode.leftChild = newLeaf;           // This is the new last node
        }
        return node;                                  // No need to rebalance
      }
    }
  }

/**
 * Used recursively to remove a new element below an AVL tree node.
 * @param o the object to remove.  Must be a <code>Comparable</code>.
 * @param node the root of the subtree under which the object <code>o</code>
 *    is to be removed.
 * @return The root of the subtree after the element has been removed.
 * Will be just <code>node</code> unless an AVL tree rebalancing occurred
 * at the node.
 */
  private AvlTreeNode removeBelow( Comparable o, AvlTreeNode node ) {
    int i = o.compareTo( node.getObject() );
    if ( i==0 ) {
      if ( node.hasLeftChild() || node.hasRightChild() ) {
        AvlTreeNode replace = node.hasLeftChild() ? node.getPredecessor()
                                                  : node.getSuccessor();
        Comparable replaceObject = replace.getObject();
        AvlTreeNode newRoot = removeBelow( replaceObject, node );
        node.setObject( replaceObject );
        return newRoot;
      }
      else {
        // Remove this leaf
        AvlTreeNode predecessor = node.leftChild();
        AvlTreeNode successor = node.rightChild();
        if ( predecessor.isSentinal() ) {
          sentinalNode.setRightChild( successor );
        }
        if ( successor.isSentinal() ) {
          sentinalNode.setLeftChild( predecessor );
        }
        isRemoved = true;
        if ( predecessor.isSentinal() ||
              (predecessor.height()>successor.height() && !successor.isSentinal()) ) {
          return predecessor;
        }
        else {
          return successor;
        }
      }
    }
    else if ( i<0 ) {
      if ( !node.hasLeftChild() ) {
        return node;                  // Object is not present
      }
      // Remove from left subbranch
      node.setLeftChild( removeBelow( o, node.leftChild() ) );
      if ( node.getLeftChildHeight() < node.getRightChildHeight()-1 ) {
        // Need to rebalance the AVL tree at this node
        AvlTreeNode m = node.rightChild();
        if ( m.getRightChildHeight() >= m.getLeftChildHeight() ) {
          return ( leftRotate( node ) );
        }
        else {
          node.setRightChild( rightRotate(m) );
          node.setHeight( 1 + node.rightChild().height() );
          return ( leftRotate( node ) );
        }
      }
      else {
        node.calcHeight();
        return node;
      }
    }
    else {
      if ( !node.hasRightChild() ) {
        return node;                  // Object is not present
      }
      // Remove from right subbranch
      node.setRightChild( removeBelow( o, node.rightChild() ) );
      if ( node.getRightChildHeight() < node.getLeftChildHeight()-1 ) {
        // Need to rebalance the AVL tree at this node
        AvlTreeNode m = node.leftChild();
        if ( m.getLeftChildHeight() >= m.getRightChildHeight() ) {
          return ( rightRotate( node ) );
        }
        else {
          node.setLeftChild( leftRotate(m) );
          node.setHeight( 1 + node.leftChild().height() );
          return ( rightRotate( node ) );
        }
      }
      else {
        node.calcHeight();
        return node;
      }
    }
  }

/**
 * Perform a left rotation.
 * This routine will be called only if the right child of n exists.
 * @return the new root node of the rotated nodes.
 */
  private AvlTreeNode leftRotate( AvlTreeNode n ) {
    AvlTreeNode m = n.rightChild();
    if ( m.leftChild() != n ) {
      // if the right child of n has a left child
      n.rightChild = m.leftChild();
      m.leftChild = n;
      n.setHeight( 1 + Math.max(n.getLeftChildHeight(), n.rightChild().height()) );
    }
    else {
      // if the right child of n does not have a left child
      n.setHeight( 1 + n.getLeftChildHeight() );
    }
    m.setHeight( 1 + Math.max(n.height(), m.getRightChildHeight()) );
    return m;
  }

/**
 * Perform a right rotation.
 * This routine will be called only if the left child of n exists.
 * @return the new root node of the rotated nodes.
 */
  private AvlTreeNode rightRotate( AvlTreeNode n ) {
    AvlTreeNode m = n.leftChild;
    if ( m.rightChild() != n ) {
      // if the left child, m, of n has a right child
      n.leftChild = m.rightChild();
      m.rightChild = n;
      n.setHeight( 1 + Math.max(n.getRightChildHeight(), n.leftChild().height()) );
    }
    else {
      // if the left child of n does not have a right child
      n.setHeight( 1 + n.getRightChildHeight() );
    }
    m.setHeight( 1 + Math.max(n.height(), m.getLeftChildHeight()) );
    return m;
  }


/**
 * A node in an AVL tree.  This class is private and an inner
 * class of <code>ThreadedAvlTree</code>.
 * <P>
 * The height value is
 * equal to zero for leaves, equal to -1 for the sentinal, and
 * equal to length of the longest path to a leaf for inner
 * nodes.
 * <P>
 * The right and left children may be replaced by references
 * to the next and previous nodes in inorder traversal order
 * when the corresponding child does not exist.
 */
  private class AvlTreeNode
  {
    Comparable theObject;
    AvlTreeNode leftChild;
    AvlTreeNode rightChild;
    int theHeight;

    private AvlTreeNode( ) {
      this( (Comparable)null );
    }

/**
 * Main constructor for AvlTreeNode's.  Generally speaking, you should
 * not change the object stored at a node in an AVL tree, so there is
 * no way to specify an object as being stored at a node, except via
 * this constructor.
 */
    private AvlTreeNode( Comparable o ) {
      theObject = o;
      leftChild = null;
      rightChild = null;
      theHeight = 0;
    }

/**
 * Returns the object (or key) in the Avl Tree.
 */
    private Comparable getObject() {
      return theObject;
    }

/**
 * Gets the height of the subtree rooted at the <code>AvlTreeNode</code>
 */
    private int height() {
      return theHeight;
    }

/**
 * Returns the left child of the AVL tree node.
 * There is no check whether the left child actually exists, so it
 * may instead return the previous object in threaded order.  Use
 * <code>hasLeftChild()</code> to determine if the left child exists.
 */
    private AvlTreeNode leftChild() {
      return leftChild;
    }

/**
 * Returns the right child of the AVL tree node.
 * There is no check whether the right child actually exists, so it
 * may instead return the next object in threaded order.  Use
 * <code>hasRightChild()</code> to determine if the right child exists.
 */
    private AvlTreeNode rightChild() {
      return rightChild;
    }

/**
 * Checks whether this is the sentinal node.
 */
    private boolean isSentinal() {
      return ( theHeight<0 );
    }

/**
 * Checks whether the node has a right child.  Returns false for the
 * sentinal node.
 */
    private boolean hasRightChild() {
      return ( theHeight > rightChild.height() && !rightChild.isSentinal() );
    }

/**
 * Checks whether the node has a left child.  Returns false for
 * the sentinal node.
 */
    private boolean hasLeftChild() {
      return ( theHeight > leftChild.height() && !leftChild.isSentinal() );
    }

/**
 * Returns the height of the right child, returning -1 if there is no
 * right child.
 */
    private int getRightChildHeight() {
      return hasRightChild() ? rightChild.height() : -1;
    }

/**
 * Returns the height of the left child, returning -1 if there is no
 * right child.
 */
    private int getLeftChildHeight() {
      return hasLeftChild() ? leftChild.height() : -1;
    }

/**
 * Sets the height of the subtree rooted at this node
 */
    private void setHeight( int h ) {
      theHeight = h;
    }

/**
 * Sets the left child.
 */
    private void setLeftChild( AvlTreeNode c ) {
      leftChild = c;
    }

/**
 * Sets the right child.
 */
    private void setRightChild( AvlTreeNode c ) {
      rightChild = c;
    }

/**
 * Sets both children
 */
    private void setChildren( AvlTreeNode left, AvlTreeNode right ) {
      leftChild = left;
      rightChild = right;
    }

/**
 * Updates the height to one plus the maximum height of its children
 */
    private int calcHeight() {
      int newHeight = -1;
      if ( !leftChild.isSentinal() ) {
        newHeight = getLeftChildHeight();
      }
      if ( (!rightChild.isSentinal()) && getRightChildHeight()>newHeight ) {
        newHeight = getRightChildHeight();
      }
      theHeight = 1 + newHeight;
      return theHeight;
    }

/**
 * Set the object in the AvlTreeNode.  For internal use only!
 */
    private void setObject( Comparable o ) {
      theObject = o;
    }

/**
 * Copy the object from AVL tree node into another.  This performs
 * a shallow copy only.
 */
    private void copyObject( AvlTreeNode source ) {
      theObject = source.theObject;
    }

/**
 * Finds the inorder successor to the node.
 */
    private AvlTreeNode getSuccessor() {
      if ( !hasRightChild() ) {
        return rightChild;
      }
      else {
        AvlTreeNode n = rightChild;
        while ( n.hasLeftChild() ) {
          n = n.leftChild();
        }
        return n;
      }
    }

/**
 * Finds the inorder predecessor to the node.
 */
    private AvlTreeNode getPredecessor() {
      if ( !hasLeftChild() ) {
        return leftChild;
      }
      else {
        AvlTreeNode n = leftChild;
        while ( n.hasRightChild() ) {
          n = n.rightChild();
        }
        return n;
      }
    }

  }   // End of AvlTreeNode subclass

  private class AvlIterator implements Iterator {
    private int iteratorModCount;
    private AvlTreeNode prevNode;    // Will be equal to null if not available
    private AvlTreeNode nextNode;

    private AvlIterator(){
      iteratorModCount = modCount;
      prevNode = null;
      nextNode = sentinalNode.rightChild();
    }

    public boolean hasNext() {
      if ( iteratorModCount != modCount ) {
        throw new ConcurrentModificationException();
      }
      return ( nextNode!=sentinalNode );
    }

    public Object next() {
      if ( !hasNext() ) {
        throw new NoSuchElementException();
      }
      prevNode = nextNode;
      Object o = nextNode.getObject();
      nextNode = nextNode.getSuccessor();
      return ( o );
    }

/**
 * Remove an element from an AVL tree set.  The element removed is the last
 * one returned by the iterator.  This command will fail if there was no
 * call to <code>next()</code> since either the iterator was created or
 * since the previous <code>remove()</code> invocation.
 * @throws UnsupportedOperationException if remove has not been implemented
 * @throws IllegalStateException if there has been no call to <code>add()</code>
 *    or if there has been no call <code>add()</code> since the last call to
 *    <code>remove()</code>.
 */
    public void remove() {
      if ( modCount != iteratorModCount ) {
        throw new ConcurrentModificationException();
      }
      if ( numElements==0 || prevNode==null ) {
        throw new IllegalStateException();
      }
      boolean careNeeded = false;
      if ( !nextNode.hasRightChild() && nextNode.leftChild==prevNode ) {
        careNeeded = true;
      }
      if ( ThreadedAvlTree.this.remove( prevNode.getObject() ) ) {
        iteratorModCount = modCount;
        if ( careNeeded && prevNode.theObject==nextNode.theObject ) {
          nextNode = prevNode;
        }
      }
      prevNode = null;
    }

  }   // End of AvlIterator class

/**
 * Find a more-or-less randomly chosen member of the Avl tree.
 */
  protected Object getRandomWalkElement( ) {
    return getRandomWalkElement(rootNode).getObject();
  }

  protected AvlTreeNode getRandomWalkElement( AvlTreeNode startNode ) {
    double rand = Math.random();
    int leftHgt = startNode.getLeftChildHeight();
    int rightHgt = startNode.getRightChildHeight();
    double leftSz = Math.pow(1.3, (double)(1+leftHgt));
    double rightSz = Math.pow(1.3, (double)(1+rightHgt));
    double denom = 1.0+leftSz+rightSz;
    AvlTreeNode retNode = sentinalNode;
    if ( rand<leftSz/denom ) {
      if ( startNode.hasLeftChild() ) {
        return getRandomWalkElement(startNode.leftChild());
      }
      else {
        retNode = startNode.leftChild;  // Return this unless its the sentinal.
      }
    }
    else if ( rand < (leftSz+rightSz)/denom ) {
      if ( startNode.hasRightChild() ) {
        return getRandomWalkElement(startNode.rightChild());
      }
      else {
        retNode = startNode.rightChild; // Return this, unless its the sentinal.
      }
    }
    if ( retNode == sentinalNode ) {
      return startNode;
    }
    else {
      return retNode;
    }
  }

/**
 * Checks the AVL tree for the AVL tree properties.  I find this handy to use
 * for testing: during testing, I can call this routine after every add() or
 * remove() call.  Then, the minute the tree becomes malformed due to a programming
 * error, I will know about it.  This will tell me which add() or remove()
 * failed, and this lets me know what needs to be debugged.
 *    You should use this only for testing, not for the final runs of your
 * programming.  Note that a single call to the checkAvlProperties() function
 * takes O(numElements) time.
 *
 * I used sentinals in my code; however, now that I have coded up the routines
 * in sentinals, it is probably actually better to not bother with a sentinal.
 * This means however, that your code for checking the AVL tree properties will
 * need to be different from mine.  (And if you use sentinals, you will probably
 * implement them differently than I did.)  However, you may use the code below
 * as an example of how to recursively check AVL tree properties, and as a
 * guideline for writing your own version for testing your own program.
 *
 * @author Sam Buss
 * @date September 2000
 */
  protected void checkAvlProperties() {
    if ( numElements==0 ) {
      if ( sentinalNode.rightChild!=null || sentinalNode.leftChild!=null ) {
        throw new IllegalStateException();
      }
    }
    else {
      checkAvlProperties( rootNode, null, null );
    }
  }

  protected void checkAvlProperties( AvlTreeNode node, Object leftBound, Object rightBound ) {
    if ( (leftBound!=null && ((Comparable)(node.getObject())).compareTo(leftBound)<=0)
        || (rightBound!=null && ((Comparable)(node.getObject())).compareTo(rightBound)>=0) ) {
      throw new IllegalStateException();
    }
    int leftHgt = node.getLeftChildHeight();    // Height of left child, or -1 if none
    int rightHgt = node.getRightChildHeight();  // Height of right child, or -1 if none
    int h = node.theHeight;
    if ( h!=1+Math.max(leftHgt,rightHgt) ) {  // If the height is wrong
      throw new IllegalStateException();
    }
    if ( h > 2+leftHgt || h>2+rightHgt ) {    // If the AVL balance property not met
      throw new IllegalStateException();
    }
    if ( !node.leftChild.isSentinal() ) {
      // If has an inorder predecessor, check that preceding node's key is less than this node's
      if ( !(node.leftChild.theObject.compareTo(node.theObject)<0) ) {
        throw new IllegalStateException();
      }
    }
    if ( node.hasLeftChild() ) {
      if ( leftHgt<0 ) {
        throw new IllegalStateException();
      }
      // Recursively check the AVL properties below the left child
      checkAvlProperties( node.leftChild(), leftBound, node.getObject() );
    }
    else if ( !node.leftChild.isSentinal() ) {  // If has a thread pointer on left
      // Verify the thread pointer
      // getSuccessor() works like Wiess's findMin(rightChild()).
      if ( node != node.leftChild.getSuccessor() ) {
        throw new IllegalStateException();
      }
    }
    else if ( sentinalNode.rightChild!=node ) {   // If not the correct first element
      throw new IllegalStateException();
    }
    if ( !node.rightChild.isSentinal() ) {
      // If has an inorder successor, check this node's key is less than the next's
      if ( !(node.theObject.compareTo(node.rightChild.theObject)<0) ) {
        throw new IllegalStateException();
      }
    }
    if ( node.hasRightChild() ) {
      if ( rightHgt<0 ) {
        throw new IllegalStateException();
      }
      // Recursively check the Avl properties below the right child.
      checkAvlProperties( node.rightChild(), node.getObject(), rightBound );
    }
    else if ( !node.rightChild.isSentinal() ) {  // If has a thread pointer on right
      // Verify the thread pointer
      //  getPredecessor() works like Weiss's  findMax(leftChild())
      if ( node != node.rightChild.getPredecessor() ) {
        throw new IllegalStateException();
      }
    }
    else if ( sentinalNode.leftChild!=node ) {   // If not the correct last element
      throw new IllegalStateException();
    }
  }
}

