Please send questions to st10@humboldt.edu .
/************************************************************/
/* implementation of .h file adapted from                   */
/* http://www.cs.colorado.edu/~main/chapter10/bt_class.h    */
/*                                                          */
/* Main and Savitch, "Data Structures and Other Objects     */
/*    using C++", 2nd edition, Addison-Wesley, Ch.10,Ch.11  */
/************************************************************/

//-----------------------------------------------------------
// File: complete_tree.template
// Name: Sharon Tuttle
//       (implementing an adaptation of a .h file adapted from
//       Savitch and Main)
// last modified: 4-12-05
//
// Template Class: complete_tree<Item> (a complete binary tree 
//                 where each node contains an Item)
//    See complete_tree.h for documentation.
//
// Because this is a template class, it is included in
//    the header file, and not compiled separately.
//
// INVARIANT for the complete_tree class:
//   1. The items in the complete tree are stored in a 
//      dynamic array, where the root is in index 0, depth
//      1 would be in indices 1-2, depth 2 would be in indices
//      3-6, ,,, depth n would (2 exp n)-1, ... (2 exp (n+1))-2.
//   2. The current capacity of the complete_tree is
//      stored in capacity; the current number of items is
//      stored in used.
//   3. Each non-empty complete_tree instance always has a
//      "current node" --- the member variable current_index 
//      contains the index of this node.
//--------------------------------------------------------------

#include <cassert>             // Provides assert
#include <algorithm>           // Provides copy function
#include <iomanip>	       // Provides setw
#include <iostream>            // Provides cout
#include <cstdlib>             // Provides size_t
using namespace std;

/********************************************************/
/* CONSTRUCTORS and DESTRUCTOR                          */
/********************************************************/

// constructor 
//
// postcondition: creates an empty complete tree instance
//    (with no nodes).
//
template <typename Item>
complete_tree<Item>::complete_tree( )
{
    nodes = new Item[1];   // initial complete tree has room
                           //    for one node
    capacity = 1;
    used = 0;
    current_index = -1;    // there's no current until there's
                           //    a node...
}

// copy constructor
//
// Library facilities used: algorithm
template <typename Item>
complete_tree<Item>::complete_tree(const complete_tree<Item>& source) 
{
    nodes = new Item[source.capacity];

    capacity = source.capacity;
    used = source.used;

    // (copy is from the algorithm library)
    copy(source.nodes, source.nodes + used, nodes);

    // what should current_index for new copy contain?
    //    If copied an empty tree, current_index is -1;
    //    otherwise, we'll start it at the root, I think.
    if (used == 0)
    {
        current_index = -1;
    }
    else
    {
        current_index = 0;
    }
}

// destructor
//
template <typename Item>
complete_tree<Item>::~complete_tree()
{
    delete [ ] nodes;
} 

/*************************************************************/
/* ACCESSORS and other constant member functions (observers) */
/*************************************************************/

// get_size
//
// postcondition: returns the number of nodes in the 
//    complete_tree.
//
template <typename Item>
size_t complete_tree<Item>::get_size( ) const
{
    return used;
}

// is_empty
//
// postcondition: returns true if the complete_tree is
//    empty, returns false otherwise.
//
template <typename Item>
bool complete_tree<Item>::is_empty( ) const
{
    return (used == 0);
}

// retrieve
//
// precondition: size( ) > 0
// postcondition: returns (non-destructively) the data 
//    from the "current node", BUT the complete_tree is
//    unchanged.
//
template <typename Item>
Item complete_tree<Item>::retrieve( ) const
{
    assert(get_size( ) > 0);

    return nodes[current_index];
}

// is_root
//
// postcondition: returns true if size( ) > 0 and 
//    and the "current node" is the root.
//
template <typename Item>
bool complete_tree<Item>::is_root( ) const
{
    return( (get_size( ) > 0) && (current_index == 0) );
}

// is_leaf
//
// postcondition: returns true if size( ) > 0 and
//    the "current node" is a leaf (has no children)
//
template <typename Item>
bool complete_tree<Item>::is_leaf( ) const
{
    return( (get_size( ) > 0) &&
            (! has_left_child( ) ) &&
            (! has_right_child( ) ) );
}

// has_parent
//
// postcondition: returns true if size( ) > 0 and
//    the "current node" has a parent.
//
template <typename Item>
bool complete_tree<Item>::has_parent( ) const
{
    return ( (get_size( ) > 0) &&
             // if current isn't root, it must have a parent!
             (current_index != 0) );
}

// has_left_child
//
// postcondition: returns true if size( ) > 0 and
//    the "current node" has a left child.
//
template <typename Item>
bool complete_tree<Item>::has_left_child( ) const
{
    return ( (get_size( ) > 0) &&
             
             // see if where left child SHOULD be is
             //    currently filled
             ( get_left_index( ) < used ) );
}

// has_right_child
//
// postcondition: returns true if size( ) > 0 and
//    the "current node" has a right child.
//
template <typename Item>
bool complete_tree<Item>::has_right_child( ) const
{
    return ( (get_size( ) > 0) &&
             
             // see if where right child SHOULD be is
             //    currently filled
             ( get_right_index( ) < used ) );
}

// get_parent_value
//
// precondition: has_parent( ) == true
// postcondition: returns the value of "current 
//    node"'s parent
//
template <typename Item>
Item complete_tree<Item>::get_parent_value( ) const
{
    assert( has_parent( ) == true );

    return nodes[ get_parent_index( ) ];
}

// get_left_value
//
// precondition: has_left_child( ) == true
// postcondition: returns the value of the
//    "current node"'s left child
//
template <typename Item>
Item complete_tree<Item>::get_left_value( ) const
{
    assert( has_left_child( ) == true );

    return nodes[ get_left_index( ) ];
}

// get_right_value
//
// precondition: has_right_child( ) == true
// postcondition: returns the value of the
//    "current node"'s right child
//
template <typename Item>
Item complete_tree<Item>::get_right_value( ) const
{
    assert( has_right_child( ) == true );

    return nodes[ get_right_index( ) ];
}

/****************************************************/
/* MODIFIERS and other modifying member functions   */
/****************************************************/

// add
//
// postconditions: a node has been added to the proper
//    (next moving right) position at the lowest level 
//    to maintain this as a complete binary tree, with
//    the given entry as its value.
//       IF the tree was EMPTY before, then current node
//    is now the root. Otherwise, current node
//    is unchanged.
//
// Library facilities used: algorithm
//
template <typename Item>
void complete_tree<Item>::add(const Item& entry)
{
    Item *larger_nodes;

    if (used == capacity)
    {
        // want to add a new level to tree --- and in a 
        //    complete binary tree, that new level might
        //    eventually contain one more than the current
        //    capacity
        capacity += (capacity+1);

        larger_nodes = new Item[capacity];
        copy(nodes, nodes + used, larger_nodes); // from algorithm 
                                                 //    library

        delete [ ] nodes;
        nodes = larger_nodes;
    }

    // if tree is currently empty, then adding this node
    //    should elso set "current index" to the newly-added
    //    root.
    if ( is_empty( ) )
    {
        current_index = 0;
    }

    // "next" node to be filled in the complete tree is
    //    the next to the right on the lowest level ---
    //    the node at index used!
    nodes[used] = entry;
    used++;
}

// remove
//
// preconditions: size( ) > 0
// postconditions: the rightmost node on the lowest level
//    of the tree has been removed, and its value is
//    returned.
//       IF the tree is now empty, then there is no longer
//    a "current node"
//       IF "current node" WAS the node to be removed, then
//    "current node" is now that removed node's parent.
//       OTHERWISE, "current_node" is unchanged.
//
template <typename Item>
Item complete_tree<Item>::remove( )
{
    Item removed_value;

    assert( get_size( ) > 0 );

    removed_value = nodes[used-1];
    used--;

    // does current_index need to be changed?
    if ( used == 0 )
    {
        // tree is now empty, so there is no longer
        //    a "current node"
        current_index = -1; 
    }
    else if ( used == current_index )
    {
        // just removed "current node" --- make its
        //    parent the new "current node"
        // (and note tree cannot be empty, if reached here)
        current_index = get_parent_index( );
    }

    return removed_value;
}

// change
//
// precondition: size( ) > 0
// postcondition: the data at the "current node" has
//    been changed to the new entry
//
template <typename Item>
void complete_tree<Item>::change(const Item& entry)
{
    assert( get_size( ) > 0 );

    nodes[current_index] = entry;
}

// clear_tree
//
// postconditions: the tree is empty (and so there is
//    no "current node")
//
template <typename Item>
void complete_tree<Item>::clear_tree( )
{
    delete [ ] nodes;

    nodes = new Item[1];
    capacity = 1;
    used = 0;
    current_index = -1;
}

// shift_to_root
//
// precondition: size( ) > 0
// postcondition: the "current node" is now the root
//    of the tree.
//
template <typename Item>
void complete_tree<Item>::shift_to_root( )
{
    assert( get_size( ) > 0 );

    current_index = 0;
}

// shift_up
//
// precondition: has_parent( ) == true
// postcondition: the "current node" has been shifted
//    up to the parent of the old current node.
//
template <typename Item>
void complete_tree<Item>::shift_up( )
{
    assert( has_parent( ) == true );

    current_index = get_parent_index( );
}

// shift_left
//
// precondition: has_left_child( ) == true
// postcondition: the "current node" has been shifted
//    down to the left child of the old current node.
//
template <typename Item>
void complete_tree<Item>::shift_left( )
{
    assert( has_left_child( ) == true );

    current_index = get_left_index( );
}


// shift_right
//
// precondition: has_right_child( ) == true
// postcondition: the "current node" has been shifted
//    down to the right child of the old current node.
//
template <typename Item>
void complete_tree<Item>::shift_right( )
{
    assert( has_right_child( ) == true );

    current_index = get_right_index( );
}

// shift_to_lowest_right
//
// precondition: size( ) != 0
// postcondition: the "current node" has been shifted
//    down to the rightmost item on the lowest level
//
template <typename Item>
void complete_tree<Item>::shift_to_lowest_right( )
{
    assert( get_size( ) > 0 );

    current_index = used-1;
}


// print_tree
//
// preconditions: if !empty( ), depth is the depth of the 
//    calling complete_tree instance. 
// postconditions: if  !empty, then the contents of the 
//    root and all of its descendants have been written to 
//    cout with the << operator using a backward in-order 
//    traversal. Each node is indented four times its depth.
//
template <typename Item>
void complete_tree<Item>::print_tree(size_t depth)
{
    print(0, depth);
}

/****************************************************/
/* OVERLOADED OPERATORS                             */
/****************************************************/

// =
//
// postcondition: the complete_tree that activated this 
//    will be made to have the same items as source
//
// Library facilities used: algorithm
//
template <typename Item>
void complete_tree<Item>::operator =(const complete_tree<Item>& source) 
{
    Item *new_nodes;

    if (this == &source) // Handle self-assignment
    {
        return;
    }

    // If needed, allocate an array with a different size:
    if (capacity != source.capacity)
    { 
        new_nodes = new Item[source.capacity];
        delete [ ] nodes;
        nodes = new_nodes;
        capacity = source.capacity;
    }

    // Copy the data from the source array:
    used = source.used;
    copy(source.nodes, source.nodes + used, nodes); // from 
                                                    //algorithm lib
    
    // where should current_ptr for new copy point?
    //    If copied an empty tree, current_index is -1
    //    otherwise, we'll start it at the root, I think.
    if (used == 0)
    {
        current_index = -1;
    }
    else
    {
        current_index = 0;
    }
}

/****************************************************/
/* private helper functions                         */
/****************************************************/

// get_parent_index
//
// precondition:  has_parent( ) == true
// postcondition: returns index of current node's
//    parent
//
template <typename Item>
size_t complete_tree<Item>::get_parent_index( ) const
{
    assert(has_parent( ) == true);

    return ( (current_index - 1)/ 2 );
} 

// get_left_index
//
// postcondition: returns what WOULD be index of 
//    current node's left child (BUT it may not
//    currently exist!)
//
template <typename Item>
size_t complete_tree<Item>::get_left_index( ) const
{
    return ( (2 * current_index) + 1 );
} 

// get_right_index
//
// postcondition: returns what WOULD be index of 
//    current node's right child (BUT it may not
//    currently exist!)
//
template <typename Item>
size_t complete_tree<Item>::get_right_index( ) const
{
    return ( (2 * current_index) + 2 );
} 

// print
//
// used to help accomplish print_tree
//
// Library facilities used: iomanip, iostream, stdlib
//
template <typename Item>
void complete_tree<Item>::print(size_t index, size_t depth)
{
    size_t save_current;

    save_current = current_index;

    if ((index >= 0) && (index < used) )
    {
        // get_right_index works based on current_index...!
        current_index = index;
        print( get_right_index( ), depth+1 );

        // Index 4*depth spaces
        cout << setw(4*depth) << "";
        cout << nodes[index] << endl;
        
        // get_left_index works based on current_index...!
        current_index = index;
        print( get_left_index( ), depth+1 );
    }        

    current_index = save_current;
}