BSTwithIterator.h
#ifndef BINARY_SEARCH_TREE_H
#define BINARY_SEARCH_TREE_H
#include "dsexceptions.h"
#include <algorithm>
#include <iostream>
#include <iterator>
#include <utility>
using namespace std;
template <typename Comparable>
struct BinaryNode
{
Comparable element;
BinaryNode *left;
BinaryNode *right;
BinaryNode *parent;
BinaryNode( const Comparable & theElement, BinaryNode *lt, BinaryNode *rt,
BinaryNode *par)
: element{ theElement }, left{ lt }, right{ rt }, parent { par } { }
/* BinaryNode( Comparable && theElement, BinaryNode *lt, BinaryNode *rt,
BinaryNode *par)
: element{ std::move( theElement ) },
left{ lt }, right{ rt }, parent{ par } { } */
};
template <typename Comparable>
class BinarySearchTree
{
public:
class BstIterator : public std::iterator<std::bidirectional_iterator_tag, Comparable> {
public:
typedef Comparable value_type;
BstIterator();
// comparison operators. just compare node pointers
bool operator== (const BstIterator& rhs) const;
bool operator!= (const BstIterator& rhs) const;
// dereference operator. return a reference to
// the value pointed to by nodePtr
const Comparable& operator* () const;
// preincrement. move forward to next larger value
BstIterator& operator++ ();
// postincrement
BstIterator operator++ (int);
// predecrement. move backward to largest value < current value
BstIterator operator-- ();
// postdecrement
BstIterator operator-- (int);
private:
friend class BinarySearchTree<Comparable>;
// nodePtr is the current location in the tree. we can move
// freely about the tree using left, right, and parent.
// tree is the address of the stree object associated
// with this iterator. it is used only to access the
// root pointer, which is needed for ++ and --
// when the iterator value is end()
const BinaryNode<Comparable> *nodePtr;
const BinarySearchTree<Comparable> *tree;
// used to construct an iterator return value from
// a node pointer
BstIterator (const BinaryNode<Comparable> *p,
const BinarySearchTree<Comparable> *t);
};
typedef BstIterator const_iterator;
typedef const_iterator iterator;
BinarySearchTree( ) : root{ nullptr }
{
}
/**
* Copy constructor
*/
BinarySearchTree( const BinarySearchTree & rhs ) : root{ nullptr }
{
root = clone( rhs.root );
}
/**
* Move constructor
*/
BinarySearchTree( BinarySearchTree && rhs ) : root{ rhs.root }
{
rhs.root = nullptr;
}
/**
* Destructor for the tree
*/
~BinarySearchTree( )
{
makeEmpty( );
}
/**
* Copy assignment
*/
BinarySearchTree & operator=( const BinarySearchTree & rhs )
{
BinarySearchTree copy = rhs;
std::swap( *this, copy );
return *this;
}
/**
* Move assignment
*/
BinarySearchTree & operator=( BinarySearchTree && rhs )
{
std::swap( root, rhs.root );
return *this;
}
/**
search for item. if found, return an iterator pointing
at it in the tree; otherwise, return end()
*/
const_iterator find(const Comparable& item) const;
/**
* return an iterator pointing to the first item (inorder)
*/
const_iterator begin() const;
/**
* return an iterator pointing just past the end of
* the tree data
*/
const_iterator end() const;
/**
* Find the smallest item in the tree.
* Throw UnderflowException if empty.
*/
const Comparable & findMin( ) const
{
if( isEmpty( ) )
throw UnderflowException{ };
return findMin( root )->element;
}
/**
* Find the largest item in the tree.
* Throw UnderflowException if empty.
*/
const Comparable & findMax( ) const
{
if( isEmpty( ) )
throw UnderflowException{ };
return findMax( root )->element;
}
/**
* Returns true if x is found in the tree.
*/
bool contains( const Comparable & x ) const
{
return contains( x, root );
}
/**
* Test if the tree is logically empty.
* Return true if empty, false otherwise.
*/
bool isEmpty( ) const
{
return root == nullptr;
}
/**
* Print the tree contents in sorted order.
*/
void printTree( ostream & out = cout ) const
{
if( isEmpty( ) )
out << "Empty tree" << endl;
else
printTree( root, out );
}
/**
* Make the tree logically empty.
*/
void makeEmpty( )
{
makeEmpty( root );
}
/**
* Insert x into the tree; duplicates are ignored.
*/
const_iterator insert( const Comparable & x )
{
auto t = insert( x, root , nullptr);
if (t == nullptr)
return end();
else
return const_iterator(t, this);
}
/**
* Insert x into the tree; duplicates are ignored.
*/
/* void insert( Comparable && x )
{
insert( std::move( x ), root, nullptr );
}*/
/**
* Remove x from the tree. Nothing is done if x is not found.
*/
void remove( const Comparable & x )
{
remove( x, root );
}
private:
BinaryNode<Comparable> *root;
/**
* Internal method to insert into a subtree.
* x is the item to insert.
* t is the node that roots the subtree.
* Set the new root of the subtree.
*/
BinaryNode<Comparable>* insert( const Comparable & x, BinaryNode<Comparable> * & t, BinaryNode<Comparable> * par )
{
if( t == nullptr )
{
t = new BinaryNode<Comparable>{ x, nullptr, nullptr, par };
return t;
}
else if( x < t->element )
return insert( x, t->left, t );
else if( t->element < x )
return insert( x, t->right, t );
else
return nullptr; // Duplicate; do nothing
}
/**
* Internal method to insert into a subtree.
* x is the item to insert.
* t is the node that roots the subtree.
* Set the new root of the subtree.
*/
/* void insert( Comparable && x, BinaryNode<Comparable> * & t, BinaryNode<Comparable> * par )
{
if( t == nullptr )
t = new BinaryNode<Comparable>{ std::move( x ), nullptr, nullptr, par};
else if( x < t->element )
insert( std::move( x ), t->left, t );
else if( t->element < x )
insert( std::move( x ), t->right, t );
else
; // Duplicate; do nothing
}*/
/**
* Internal method to remove from a subtree.
* x is the item to remove.
* t is the node that roots the subtree.
* Set the new root of the subtree. Return true if removed.
*/
bool remove( const Comparable & x, BinaryNode<Comparable> * & t )
{
if( t == nullptr )
return false; // Item not found; do nothing
if( x < t->element )
return remove( x, t->left );
else if( t->element < x )
return remove( x, t->right );
else if( t->left != nullptr && t->right != nullptr ) // Two children
{
t->element = findMin( t->right )->element;
remove( t->element, t->right );
return true;
}
else
{
BinaryNode<Comparable> *oldNode = t;
t = ( t->left != nullptr ) ? t->left : t->right;
delete oldNode;
return true;
}
}
/**
* Internal method to find the smallest item in a subtree t.
* Return node containing the smallest item.
*/
BinaryNode<Comparable> * findMin( BinaryNode<Comparable> *t ) const
{
if( t == nullptr )
return nullptr;
if( t->left == nullptr )
return t;
return findMin( t->left );
}
/**
* Internal method to find the largest item in a subtree t.
* Return node containing the largest item.
*/
BinaryNode<Comparable> * findMax( BinaryNode<Comparable> *t ) const
{
if( t != nullptr )
while( t->right != nullptr )
t = t->right;
return t;
}
/**
* Internal method to test if an item is in a subtree.
* x is item to search for.
* t is the node that roots the subtree.
*/
bool contains( const Comparable & x, BinaryNode<Comparable> *t ) const
{
if( t == nullptr )
return false;
else if( x < t->element )
return contains( x, t->left );
else if( t->element < x )
return contains( x, t->right );
else
return true; // Match
}
/**
* Internal method to make subtree empty.
*/
void makeEmpty( BinaryNode<Comparable> * & t )
{
if( t != nullptr )
{
makeEmpty( t->left );
makeEmpty( t->right );
delete t;
}
t = nullptr;
}
/**
* Internal method to print a subtree rooted at t in sorted order.
*/
void printTree( BinaryNode<Comparable> *t, ostream & out ) const
{
if( t != nullptr )
{
printTree( t->left, out );
out << t->element << endl;
printTree( t->right, out );
}
}
/**
* Internal method to clone subtree.
*/
BinaryNode<Comparable> * clone( BinaryNode<Comparable> *t ) const
{
if( t == nullptr )
return nullptr;
else
return new BinaryNode<Comparable>{ t->element, clone( t->left ), clone( t->right ), t->parent };
}
};
/**
search for item. if found, return an iterator pointing
at it in the tree; otherwise, return end()
*/
template <class Comparable>
typename BinarySearchTree<Comparable>::const_iterator
BinarySearchTree<Comparable>::find(const Comparable& item) const
{
auto t = root;
while (t != nullptr && !(t->element == item))
{
t = (item < t->element) ? t->left : t->right;
}
return BstIterator(t, this);
}
/**
* return an iterator pointing to the first item (inorder)
*/
template <class Comparable>
typename BinarySearchTree<Comparable>::const_iterator
BinarySearchTree<Comparable>::begin() const
{
return BstIterator(findMin(root), this);
}
/**
* return an iterator pointing just past the end of
* the tree data
*/
template <class Comparable>
typename BinarySearchTree<Comparable>::const_iterator
BinarySearchTree<Comparable>::end() const
{
return BstIterator(nullptr, this);
}
template <class Comparable>
BinarySearchTree<Comparable>::BstIterator::BstIterator()
: nodePtr(nullptr), tree(nullptr)
{
}
// comparison operators. just compare node pointers
template <class Comparable>
bool BinarySearchTree<Comparable>::BstIterator::operator== (const BstIterator& rhs) const
{
return tree == rhs.tree && nodePtr == rhs.nodePtr;
}
template <class Comparable>
bool BinarySearchTree<Comparable>::BstIterator::operator!= (const BstIterator& rhs) const
{
return tree != rhs.tree || nodePtr != rhs.nodePtr;
}
// dereference operator. return a reference to
// the value pointed to by nodePtr
template <class Comparable>
const Comparable& BinarySearchTree<Comparable>::BstIterator::operator* () const
{
if (nodePtr == nullptr)
throw UnderflowException {};
return nodePtr->element;
}
// preincrement. move forward to next larger value
template <class Comparable>
typename BinarySearchTree<Comparable>::BstIterator&
BinarySearchTree<Comparable>::BstIterator::operator++ ()
{
BinaryNode<Comparable> *p;
if (nodePtr == nullptr)
{
// ++ from end(). get the root of the tree
nodePtr = tree->root;
// error! ++ requested for an empty tree
if (nodePtr == nullptr)
throw UnderflowException { };
// move to the smallest value in the tree,
// which is the first node inorder
while (nodePtr->left != nullptr) {
nodePtr = nodePtr->left;
}
}
else
if (nodePtr->right != nullptr)
{
// successor is the farthest left node of
// right subtree
nodePtr = nodePtr->right;
while (nodePtr->left != nullptr) {
nodePtr = nodePtr->left;
}
}
else
{
// have already processed the left subtree, and
// there is no right subtree. move up the tree,
// looking for a parent for which nodePtr is a left child,
// stopping if the parent becomes NULL. a non-NULL parent
// is the successor. if parent is NULL, the original node
// was the last node inorder, and its successor
// is the end of the list
p = nodePtr->parent;
while (p != nullptr && nodePtr == p->right)
{
nodePtr = p;
p = p->parent;
}
// if we were previously at the right-most node in
// the tree, nodePtr = nullptr, and the iterator specifies
// the end of the list
nodePtr = p;
}
return *this;
}
// postincrement
template <class Comparable>
typename BinarySearchTree<Comparable>::BstIterator
BinarySearchTree<Comparable>::BstIterator::operator++ (int)
{
auto saved = *this;
operator++();
return saved;
}
// predecrement. move backward to largest value < current value
template <class Comparable>
typename BinarySearchTree<Comparable>::BstIterator
BinarySearchTree<Comparable>::BstIterator::operator-- ()
{
BinaryNode<Comparable> *p;
if (nodePtr == NULL)
{
// -- from end(). get the root of the tree
nodePtr = tree->root;
// error! -- requested for an empty tree
if (nodePtr == NULL)
throw UnderflowException("tree iterator operator--: tree empty");
// move to the largest value in the tree,
// which is the last node inorder
while (nodePtr->right != NULL)
nodePtr = nodePtr->right;
} else if (nodePtr->left != NULL)
{
// must have gotten here by processing all the nodes
// on the left branch. predecessor is the farthest
// right node of the left subtree
nodePtr = nodePtr->left;
while (nodePtr->right != NULL)
nodePtr = nodePtr->right;
}
else
{
// // must have gotten here by going right and then
// far left. move up the tree, looking for a parent
// for which nodePtr is a right child, stopping if the
// parent becomes NULL. a non-NULL parent is the
// predecessor. if parent is NULL, the original node
// was the first node inorder, and its predecessor
// is the end of the list
p = nodePtr->parent;
while (p != NULL && nodePtr == p->left)
{
nodePtr = p;
p = p->parent;
}
// if we were previously at the left-most node in
// the tree, nodePtr = NULL, and the iterator specifies
// the end of the list
! nodePtr = p;
}
return *this;
}
// postdecrement
template <class Comparable>
typename BinarySearchTree<Comparable>::BstIterator
BinarySearchTree<Comparable>::BstIterator::operator-- (int)
{
auto saved = *this;
operator--();
return saved;
}
template <class Comparable>
BinarySearchTree<Comparable>::BstIterator::BstIterator
(const BinaryNode<Comparable> *p, const BinarySearchTree<Comparable> *t)
: nodePtr(p), tree(t)
{
}
#endif
unformatted source
© 2016-2024, Old Dominion Univ.