#include <iostream.h>

template <class KeyType>
class BST
{
public:
    BST ( ); // creates a new, empty BST
    ~BST ( ); // deletes a BST
    void Insert ( KeyType ); // inserts a new node with given value
    void Remove ( KeyType ); // removes a node with given value
    bool Has ( KeyType ) const; // searches for a node with given value
    void PrintInOrder ( ) const; // prints the elements in sorted order
    bool IsEmpty ( ) const; // whether the BST contains any elements
    void Clear ( ); // removes all elements from the BST
    KeyType Maximum ( ) const; // returns the "largest" value
    KeyType Minimum ( ) const; // returns the "smallest" value
    KeyType Successor ( KeyType ) const; // returns the next "largest" value
    KeyType Predecessor ( KeyType ) const; // returns the next "smallest" value


private:
    struct bstnode
        {
        KeyType key;
        bstnode* left;
        bstnode* right;
        bstnode* parent;
        };

    bstnode* root;
    void Delete ( bstnode* ); // for use by Clear ( )
    void Print ( bstnode* ) const; // for use by PrintInOrder ( )
    bstnode* TreeMinimum ( bstnode* ) const; // for use by Minimum ( ), Remove ( )
    bstnode* TreeMaximum ( bstnode* ) const; // for use by Maximum ( ), Remove ( ) 
    bstnode* TreePredecessor ( bstnode* ) const; // for use by Predecessor ( )
    bstnode* TreeSuccessor ( bstnode* ) const; // for use by Successor ( )
    bstnode* TreeFind ( KeyType ) const; // used by Remove ( ), Successor ( ), Predecessor ( )

};

template <class KeyType>
BST <KeyType> :: BST ( )
{
    root = 0; // set to null
}


template <class KeyType>
void BST <KeyType> :: Insert ( KeyType newkey )
{
    // allocate and initialize memory for new node
    bstnode* newnode = new bstnode;
    newnode -> key = newkey;
    newnode -> left = newnode -> right = 0; // new node will be a leaf
    
    // search for appropriate insertion point
    bstnode* insertpoint = root; // will eventually be node to insert at
    bstnode* newparent = 0; // will eventually be parent of new node

    while ( insertpoint != 0 ) // traverse tree
    {
        newparent = insertpoint;
        if ( newkey < insertpoint->key )
            insertpoint = insertpoint->left;
        else
            insertpoint = insertpoint->right;
    }

    if ( newparent == 0 ) // never did any traversal
    {
        root = newnode;
        root->parent = 0;
    }

    else
    {
        newnode -> parent = newparent; 
        if ( newkey < newparent->key ) // link in as appropriate child of newparent
            newparent->left = newnode;
        else
            newparent->right = newnode;
    }
}

template <class KeyType>
bool BST <KeyType> :: Has(KeyType searchkey) const
{
    return ( TreeFind(searchkey) != 0 );
}

template <class KeyType>
void BST <KeyType> :: PrintInOrder ( ) const
{
    Print ( root );
}

template <class KeyType>
void BST <KeyType> :: Print ( bstnode* current ) const
{
    if ( current == 0 )
        return;
    Print ( current -> left );
    cout << current -> key << endl;
    Print ( current -> right );
}

template <class KeyType>
bool BST <KeyType> :: IsEmpty ( ) const
{
    return ( root == 0 );
}

template <class KeyType>
void BST <KeyType> :: Clear ( )
{
    Delete ( root );
    root = 0;
}

template <class KeyType>
void BST <KeyType> :: Delete ( bstnode* current )
{
    if ( current == 0 )
        return;
    Delete ( current -> left );
    Delete ( current -> right );
    delete current;
}

template <class KeyType>
KeyType BST <KeyType> :: Maximum ( ) const
{
    return ( TreeMaximum ( root ) ) -> key;
}

template <class KeyType>
KeyType BST <KeyType> :: Minimum ( ) const
{
    return ( TreeMinimum ( root ) ) -> key;
}


template <class KeyType>
BST < KeyType > :: bstnode* BST <KeyType> :: TreeMaximum ( bstnode* current ) const
{
    if ( current == 0 )
        // throw some exception
    bstnode* max = current;
    while ( max -> right != 0 )
        max = max -> right;
    return max;
}


template <class KeyType>
BST < KeyType > :: bstnode* BST <KeyType> :: TreeMinimum ( bstnode* current ) const
{
    if ( current == 0 )
        // throw some exception
    bstnode* min = current;
    while ( min -> left != 0 )
        min = min -> left;
    return min;
}

template <class KeyType>
BST < KeyType > :: bstnode* BST <KeyType> :: TreeFind ( KeyType searchkey ) const
{
    bstnode* current = root;

    // just like Binary Search of ordered array
    while ( current != 0 )
    {
        if ( current->key == searchkey )
            return current;
        if ( current->key <= searchkey )
            current = current->right;
        else
            current = current->left;
    }

    return 0; // never found anything
}

template <class KeyType>
KeyType BST <KeyType> :: Successor ( KeyType value ) const
{
    bstnode* answer = TreeFind ( value );
    if ( answer == 0 )
        // throw some exception; value not in BST
    answer = TreeSucessor ( answer );
    if (answer == 0)
        // throw some exception; no successor exists
    return ( answer -> key );
}

template <class KeyType>
BST < KeyType > :: bstnode* BST <KeyType> :: TreeSuccessor ( bstnode* node ) const
{
    // if node has a right subtree, want smallest entry in that subtree
    if ( node -> right != 0 )
        return TreeMinimum ( node );

    // otherwise, walk up tree until we find a node which is a left child
    bstnode* successor = node -> parent;
    while ( ( successor != 0 ) && ( node == successor->right ) )
    {
        node = successor;
        successor = successor -> parent;
    }

    return successor;
}


template <class KeyType>
KeyType BST <KeyType> :: Predecessor ( KeyType value ) const
{
    bstnode* answer = Find ( value );
    if ( answer == 0 )
        // throw some exception; value not in BST
    answer = TreePredecessor ( answer );
    if (answer == 0)
        // throw some exception; no predecessor exists
    return ( answer -> key );
}

template <class KeyType>
BST < KeyType > :: bstnode* BST <KeyType> :: TreePredecessor ( bstnode* node ) const
{
    // if node has a left subtree, want largest entry in that subtree
    if ( node -> left != 0 )
        return TreeMaximum ( node );

    // otherwise, walk up tree until we find a node which is a right child
    bstnode* predecessor = node -> parent;
    while ( ( predecessor != 0 ) && ( node == predecessor->left ) )
    {
        node = predecessor;
        predecessor = predecessor -> parent;
    }

    return predecessor;
}


template <class KeyType>
void BST <KeyType> :: Remove ( KeyType oldkey )  const
{
    bstnode* location = TreeFind ( oldkey );
    if ( location == 0 )
        // throw some exception; node to be removed is not in BST

    // select a node to splice out of the BST
    bstnode* splicenode;
    if ( ( location->left == 0 ) || ( location->right == 0 ) )
        splicenode = location;
    else
        splicenode = TreeSuccessor ( location );

    // filler is splicenode's child, if any
    bstnode* filler;
    if ( splicenode->left != 0 )
        filler = splicenode->left;
    else
        filler = splicenode->right;

    // splice out node
    if ( filler != 0 )
        filler -> parent = splicenode -> parent;

    // promote node to fill the hole left
    if ( splicenode->parent == 0 )
        root = filler;
    else if ( splicenode == (splicenode->parent)->left )
        (splicenode->parent)->left = filler;
    else
        (splicenode->parent)->right = filler;

    // copy data from node splicenode into "deleted" node
    if ( splicenode != location )
        location->key = splicenode->key;

    delete splicenode;
}

template <class KeyType>
BST < KeyType > :: ~BST ( )
{
    Clear ( );
}