#ifndef BINARY_SEARCH_TREE_H
#define BINARY_SEARCH_TREE_H
#include <iostream>
usingstd::cout;enumtraversal_order{PREORDER,INORDER,POSTORDER};template<typenameE>classBinarySearchTree;template<typenameE>classBNode{Edata;BNode<E>*left;BNode<E>*right;friendclassBinarySearchTree<E>;BNode():left(nullptr),right(nullptr){}};template<typenameE>classBinarySearchTree{public:BinarySearchTree();~BinarySearchTree();intsize();boolis_empty();boolinsert(constE&);boolremove(constE&);boolretrieve(constE&,E&);boolremove_all();voidprint(traversal_order);private:BNode<E>*root_;intnum_of_nodes_;// Helper functions to perform recursion.
intheight_helper(BNode<E>*);boolinsert_helper(BNode<E>*&,constE&);boolremove_helper(BNode<E>*&,constE&);voidremove_node(BNode<E>*&);boolretrieve_helper(BNode<E>*&,constE&,E&);voidprint_helper(BNode<E>*,traversal_order);voidremove_all_helper(BNode<E>*&);boolis_leaf_node(BNode<E>*);// Check if node it a leaf node.
boolonly_one_child(BNode<E>*);// Check if node has only one child node.
BNode<E>*get_min_ptr(BNode<E>*);// Find the pointer that points to the
// minimum value.
};template<typenameE>BinarySearchTree<E>::BinarySearchTree(){root_=nullptr;num_of_nodes_=0;}template<typenameE>BinarySearchTree<E>::~BinarySearchTree(){remove_all_helper(root_);}template<typenameE>intBinarySearchTree<E>::size(){returnnum_of_nodes_;}template<typenameE>boolBinarySearchTree<E>::is_empty(){// Return true if tree is empty, else false.
returnroot_==nullptr;}template<typenameE>boolBinarySearchTree<E>::insert(constE&kElement){// Insert an element. Call to insert helper.
returninsert_helper(root_,kElement);}template<typenameE>boolBinarySearchTree<E>::insert_helper(BNode<E>*&ptr,constE&kElement){// Recursively traverse until you reach a leaf node's child node (nullptr). Once
// reached, allocate a new node and replace the nullptr to point to that new node.
if(ptr==nullptr){// Add new node to tree.
BNode<E>*new_node=newBNode<E>;new_node->data=kElement;ptr=new_node;num_of_nodes_++;returntrue;}// Traverse
if(kElement<ptr->data)returninsert_helper(ptr->left,kElement);elseif(kElement>ptr->data)returninsert_helper(ptr->right,kElement);else// if (kElement == ptr->data)
returnfalse;}template<typenameE>boolBinarySearchTree<E>::remove(constE&kElement){// Remove an element. Call to remove helper.
if(is_empty())returnfalse;returnremove_helper(root_,kElement);};template<typenameE>boolBinarySearchTree<E>::remove_helper(BNode<E>*&ptr,constE&kElement){// Traverse ptr to the node that needs to be deleted.
if(ptr==nullptr)returnfalse;if(ptr->data==kElement){num_of_nodes_--;remove_node(ptr);returntrue;}elseif(kElement<ptr->data)returnremove_helper(ptr->left,kElement);else// if (kElement > ptr->data)
returnremove_helper(ptr->right,kElement);}template<typenameE>voidBinarySearchTree<E>::remove_node(BNode<E>*&ptr){// Remove node that the passed in pointer points to. There are three cases
// that have to be taken cared of: The node that needs to be removed (1) is
// a leaf node, (2) has only one child, or (3) has two child nodes.
if(is_leaf_node(ptr)){// If leaf node, just delete.
deleteptr;ptr=nullptr;}elseif(only_one_child(ptr)){// If node only has one child node then (depending on whether it is a right
// child or left child) set the pointer to point to the child node and
// delete the node that the pointer previously pointed to.
if(ptr->left==nullptr){// Change ptr to point to its right child and delete the node that it
// previously pointed to.
BNode<E>*to_remove=ptr;ptr=ptr->right;deleteto_remove;to_remove=nullptr;}elseif(ptr->right==nullptr){// Preform the same as above but with opposite child.
BNode<E>*to_remove=ptr;ptr=ptr->left;deleteto_remove;to_remove=nullptr;}}// Case in which there are two children.
else{// Find the minimum value of the subtree with ptr->right as root, then
// replace ptr's data with the minimum value. Finally, delete the node that
// originally had the minimum value.
BNode<E>*min=get_min_ptr(ptr->right);ptr->data=min->data;remove_helper(ptr->right,min->data);}}template<typenameE>boolBinarySearchTree<E>::is_leaf_node(BNode<E>*ptr){// Check if passed in pointer points to a leaf node.
if(ptr->left==nullptr&&ptr->right==nullptr)returntrue;returnfalse;}template<typenameE>boolBinarySearchTree<E>::only_one_child(BNode<E>*ptr){// Check if passed in pointer points to a node with only one child.
if(ptr->left==nullptr&&ptr->right!=nullptr)returntrue;if(ptr->right==nullptr&&ptr->left!=nullptr)returntrue;returnfalse;}template<typenameE>BNode<E>*BinarySearchTree<E>::get_min_ptr(BNode<E>*ptr){// Traverse the passed in pointer to the minimum value of the tree/subtree.
if(ptr->left==nullptr)returnptr;returnget_min_ptr(ptr->left);}template<typenameE>boolBinarySearchTree<E>::retrieve(constE&kElement,E&retrieved_element){// Retrieve the node's data that matches kElement. Call to retrieve_helper.
if(is_empty())returnfalse;returnretrieve_helper(root_,kElement,retrieved_element);}template<typenameE>boolBinarySearchTree<E>::retrieve_helper(BNode<E>*&ptr,constE&kElement,E&retrieved_element){// Traverse to the node the matches kElement. Returns that value.
if(ptr==nullptr)returnfalse;if(ptr->data==kElement){retrieved_element=ptr->data;returntrue;}elseif(kElement<ptr->data)returnretrieve_helper(ptr->left,kElement,retrieved_element);else// if (kElement > ptr->data)
returnretrieve_helper(ptr->right,kElement,retrieved_element);}template<typenameE>boolBinarySearchTree<E>::remove_all(){// Remove all nodes from tree. Call to remove_helper.
if(is_empty())returnfalse;remove_all_helper(root_);returntrue;}template<typenameE>voidBinarySearchTree<E>::remove_all_helper(BNode<E>*&ptr){// Traverse the tree in POSTORDER order and removes the nodes one at a time.
if(ptr==nullptr)return;remove_all_helper(ptr->left);remove_all_helper(ptr->right);deleteptr;ptr=nullptr;num_of_nodes_=0;}template<typenameE>voidBinarySearchTree<E>::print(traversal_orderorder){// Print values in the tree in the given order (preorder, inorder, or postorder).
print_helper(root_,order);cout.flush();}template<typenameE>voidBinarySearchTree<E>::print_helper(BNode<E>*ptr,traversal_orderorder){// Perform preorder, inorder, or postorder traversal.
if(ptr==nullptr)return;if(order==PREORDER){cout<<ptr->data;print_helper(ptr->left,PREORDER);print_helper(ptr->right,PREORDER);}elseif(order==INORDER){print_helper(ptr->left,INORDER);cout<<ptr->data;print_helper(ptr->right,INORDER);}elseif(order==POSTORDER){print_helper(ptr->left,POSTORDER);print_helper(ptr->right,POSTORDER);cout<<ptr->data;}}#endif