Please send questions to st10@humboldt.edu .
/* Cs132BinaryTree.java 1.1                               */
/* based on/modified from Ch. 11, "Java Structures", by   */
/*    D. Bailey, 2nd edition                              */
/* modified/adapted by Sharon Tuttle                      */
/* last modified: 4-3-03                                  */

public class Cs132BinaryTree
{
    /*------------------------------------
     fields
    -------------------------------------*/
    
    // information we want to be associated with this binary tree node 
    private Object value;     
    
    // parent of this node in the binary tree
    private Cs132BinaryTree parent;
    
    // left child of this node in the binary tree
    private Cs132BinaryTree left;
    
    // right child of this node in the binary tree
    private Cs132BinaryTree right;

    // how empty trees are represented in this particular
    // binary tree implementation
    public static final Cs132BinaryTree EMPTY = new Cs132BinaryTree();

    /*------------------------------------------------------------------
     constructors
     (note: Purpose: statements are given for unusual constructors...)
    -------------------------------------------------------------------*/

    /*--------------------------------------------------
     Cs132BinaryTree()
     Purpose: PRIVATE constructor used for generating
              an empty tree (a special Cs132BinaryTree
              instance is used for this);
              
              How strange is it for a user to not be able
              to create an empty Binary Tree? Hmm.
    ------------------------------------------------------*/
    private Cs132BinaryTree()
    {
        this.value = null;
        this.parent = null;
        
        // oddly (but intentionally), left and right
        // subtrees are set to reference EMPTY, or this,
        // rather than null; this allows programs to use
        // empty trees... (see pp. 272-273, "Java Structures")
        this.left = this;
        this.right = this;
    }
    
    /*---------------------------------------------------------
     Cs132BinaryTree(Object value)
     Purpose: create a Cs132BinaryTree that contains this value
              val in the root, and has empty left and right subtrees
              
              (note that this one ISN'T private... it is for
              public use)
    --------------------------------------------------------------*/
    public Cs132BinaryTree(Object val)
    {
        this.value = val;
        this.parent = null;
        
        // again, left and right subtrees are indicated
        // as empty with the special EMPTY tree
        this.left = EMPTY;
        this.right = EMPTY;
    }
    
    /*---------------------------------------------------------
     Cs132BinaryTree(Object val, Cs132BinaryTree lft, 
                     Cs132BinaryTree rt)
     Purpose: create a Cs132BinaryTree that contains this value
              val in the root, has lft as its left subtree, and
              has rt as its right subtree
              
              (note that this one ISN'T private... it is for
              public use)
    --------------------------------------------------------------*/
    public Cs132BinaryTree(Object val, Cs132BinaryTree lft,
                           Cs132BinaryTree rt)
    {
        // POSSIBLY NEW SYNTAX: notice that this will call
        // the 1-Object-argument constructor on behalf of
        // this new instance being constructed!
        this(val);

        // ...and, thus constructed, I can now call the
        // modifiers to reset to left and right subtrees
        // to those desired, instead of EMPTY
        this.setLeft(lft);
        this.setRight(rt);
    }
    
    /*-------------------------------------------------------
     accessors
     (note: Purpose: statements are given for accessors
     that are not completely straightforward)
    -------------------------------------------------------*/ 

    public Object getValue()
    {
        return this.value;
    }
        
    /*------------------------------------------------------
     getParent()
     Purpose: returns reference to parent node, OR returns null
              if there IS no parent
              (given this implementation, parent data field is
              already set to null if there is no parent...)
    ----------------------------------------------------------*/
    public Cs132BinaryTree getParent()
    {
        return this.parent;
    }
    
    /*------------------------------------------------------
     getLeft()
     Purpose: returns reference to left subtree, or returns null
              if there is "no" left subtree (for this implementation,
              there is "no" left subtree if it is the special EMPTY
              instance
    --------------------------------------------------------------*/
    public Cs132BinaryTree getLeft()
    {
        if (this.left == EMPTY)
        {
            return null;
        }
        else
        {
            return this.left;
        }
    }
    
    /*--------------------------------------------------------
     getRight()
     Purpose: returns reference to right subtree, or returns null
              if there is "no" right subtree (for this implementation,
              there is "no" right subtree if it is the special EMPTY
              instance
    -----------------------------------------------------------*/
    public Cs132BinaryTree getRight()
    {
        if (this.right == EMPTY)
        {
            return null;
        }
        else
        {
            return this.right;
        }
    }

    /*-------------------------------------------------------
     modifiers
     (note: Purpose: statements are given for modifiers
     that are not completely straightforward)
    -------------------------------------------------------*/ 

    public void setValue(Object newVal)
    {
        this.value = newVal;
    }

    /*-------------------------------------------------
     setParent()
     Purpose: makes parent of this tree newParent; if newParent
              happens to be EMPTY, then parent of this tree is set
              to be null instead.
    -------------------------------------------------------*/
    public void setParent(Cs132BinaryTree newParent)
    {
        if (newParent == EMPTY)
        {
            this.parent = null;
        }
        else
        {
            this.parent = newParent;
        }
    }

    /*-------------------------------------------------------
     setLeft()
     Purpose: set this tree's left subtree to be newLeft.
    
     additional complication, here! If newLeft is not EMPTY,
     then it will now have this tree as ITS parent...
    --------------------------------------------------------*/ 
    public void setLeft(Cs132BinaryTree newLeft)
    {
        // cannot make a left subtree of an empty tree...
        if (this.isEmpty())
        {
            return;   // yes, if a function has a return type
                      // of void, you can say this...
        }
        
        // what if this node currently HAS a non-empty left subtree?
        // it needs to no longer think of THIS node as its
        // parent... 
        if (this.left.getParent() == this)
        {
            left.setParent(null);
        }
        
        // finally make this the new left subtree!
        this.left = newLeft;
        
        // and --- the new left subtree now needs THIS node
        // as ITS parent...
        newLeft.setParent(this);
    }
      
    /*-------------------------------------------------
     setRight()
     Purpose: set this tree's right subtree to be newRight.
    
     additional complication, here! If newRight is not EMPTY,
     then it will now have this tree as ITS parent
    -------------------------------------------------------*/
    public void setRight(Cs132BinaryTree newRight)
    {
        // cannot make a right subtree of an empty tree...
        if (this.isEmpty())
        {
            return;   // yes, if a function has a return type
                      // of void, you can say this...
        }
        
        // what if this node currently HAS a non-empty right subtree?
        // it needs to no longer think of THIS node as its
        // parent... 
        if (this.right.getParent() == this)
        {
            right.setParent(null);
        }
        
        // finally make this the new right subtree!
        this.right = newRight;
        
        // and --- the new right subtree now needs THIS node
        // as ITS parent...
        newRight.setParent(this);
    }

    /*------------------------------------------
     overridden methods
    -------------------------------------------*/
    public String toString()
    {
        /* hmm; I think I'll have this just print the
           value in this tree's root. Wonder if that'll
           then help me with different traversals..? */
        return "Cs132BinaryTree[root value:" + this.value + "]";
    }
    
    /*----------------------------------------------------
     other methods
    ------------------------------------------------------*/
    
    /*-----------------------------------------------------
     isEmpty()
     Purpose: returns true if this is an empty binary tree?
     
     (is this useless for public, since cannot HAVE a public
     empty binary tree of this class? should it just be private,
     for use by getLeft(), getRight(), etc.?)
    --------------------------------------------------------*/
    public boolean isEmpty()
    {
       return (this == EMPTY);
    }
    
    /*--------------------------------------------------------
     valuesInOrder()
     Purpose: performs an in-order traversal of this binary
              tree, creating a String containing the String
              depiction of the objects contained within the
              tree as they would be visited in an inOrder
              traversal
    -----------------------------------------------------------*/
    public String valuesInOrder()
    {
        String result;
        
        // base case!
        if (this == EMPTY)
        {
            return "";
        }
        
        // recursive case: tree is NOT empty
        return this.left.valuesInOrder() +
               this.getValue() + " " +
               this.right.valuesInOrder();
    }
    
    /*--------------------------------------------------------
     valuesPreOrder()
     Purpose: performs a pre-order traversal of this binary
              tree, creating a String containing the String
              depiction of the objects contained within the
              tree as they would be visited in an preOrder
              traversal
    -----------------------------------------------------------*/
    public String valuesPreOrder()
    {
        String result;
        
        // base case!
        if (this == EMPTY)
        {
            return "";
        }
        
        // recursive case: tree is NOT empty
        return this.getValue() + " " +
               this.left.valuesPreOrder() +
               this.right.valuesPreOrder();
    }
  
    /*--------------------------------------------------------
     valuesPostOrder()
     Purpose: performs a post-order traversal of this binary
              tree, creating a String containing the String
              depiction of the objects contained within the
              tree as they would be visited in an postOrder
              traversal
    -----------------------------------------------------------*/
    public String valuesPostOrder()
    {
        String result;
        
        // base case!
        if (this == EMPTY)
        {
            return "";
        }
        
        // recursive case: tree is NOT empty
        return 
               this.left.valuesPostOrder() +
               this.right.valuesPostOrder() +
               this.getValue() + " ";
    }
  
} // end of class Cs132BinaryTree