namespace lasd { template BST::BST(const LinearContainer& lc){ for(ulong i=0 ; i BST::BST(const BST& bst) : BinaryTreeLnk(bst){} template BST::BST(BST&& bst) noexcept : BinaryTreeLnk(std::move(bst)){} template BST::~BST(){ BinaryTreeLnk::Clear(); } template BST& BST::operator=(const BST& bst){ BinaryTreeLnk::operator=(bst); return *this; } template BST& BST::operator=(BST&& bst) noexcept{ BinaryTreeLnk::operator=(std::move(bst)); return *this; } template bool BST::operator==(const BST& bst) const noexcept{ if(size != bst.Size()) return false; BTInOrderIterator itr1(*this); BTInOrderIterator itr2(bst); for(; !itr1.Terminated() ; ++itr1, ++itr2){ if(*itr1 != *itr2) return false; } return true; } template bool BST::operator!=(const BST& bst) const noexcept{ return !(*this == bst); } template void BST::Insert(const Data& data) noexcept{ NodeLnk*& pointer = FindPointerTo(root, data); if(pointer == nullptr){ pointer = BinaryTreeLnk::CreateNode(data); size++; } } template void BST::Insert(Data&& data) noexcept{ NodeLnk*& pointer = FindPointerTo(root, data); if(pointer == nullptr){ pointer = new NodeLnk(); std::swap(pointer->value, data); size++; } } template void BST::Remove(const Data& data) noexcept{ delete Detach(FindPointerTo(root,data)); } template const Data& BST::Min() const{ if(root == nullptr) throw std::length_error("Empty tree!"); return FindPointerToMin(root)->Element(); } template Data BST::MinNRemove(){ if(root == nullptr) throw std::length_error("Empty tree!"); return DataNDelete(DetachMin(root)); } template void BST::RemoveMin(){ if(root == nullptr) throw std::length_error("Empty tree!"); delete DetachMin(root); } template const Data& BST::Max() const{ if(root == nullptr) throw std::length_error("Empty tree!"); return FindPointerToMax(root)->Element(); } template Data BST::MaxNRemove(){ if(root == nullptr) throw std::length_error("Empty tree!"); return DataNDelete(DetachMax(root)); } template void BST::RemoveMax(){ if(root == nullptr) throw std::length_error("Empty tree!"); delete DetachMax(root); } template const Data& BST::Predecessor(const Data& data) const{ NodeLnk* const* ptr = FindPointerToPredecessor(root, data); if(ptr!=nullptr){ return (*(*ptr)).Element(); }else{ throw std::length_error("Predecessor not found!"); } } template Data BST::PredecessorNRemove(const Data& data){ NodeLnk** ptr = FindPointerToPredecessor(root,data); if(ptr!=nullptr){ return DataNDelete(Detach(*ptr)); }else{ throw std::length_error("Predecessor not found!"); } } template void BST::RemovePredecessor(const Data& data){ NodeLnk** ptr = FindPointerToPredecessor(root,data); if(ptr!=nullptr){ delete Detach(*ptr); }else{ throw std::length_error("Predecessor not found!"); } } template const Data& BST::Successor(const Data& data) const{ NodeLnk* const* ptr = FindPointerToSuccessor(root, data); if(ptr!=nullptr){ return (*(*ptr)).Element(); }else{ throw std::length_error("Successor not found!"); } } template Data BST::SuccessorNRemove(const Data& data){ NodeLnk** ptr = FindPointerToSuccessor(root,data); if(ptr!=nullptr){ return DataNDelete(Detach(*ptr)); }else{ throw std::length_error("Successor not found!"); } } template void BST::RemoveSuccessor(const Data& data){ NodeLnk** ptr = FindPointerToSuccessor(root,data); if(ptr!=nullptr){ delete Detach(*ptr); }else{ throw std::length_error("Successor not found!"); } } template bool BST::Exists(const Data& data) const noexcept{ return (FindPointerTo(root, data) != nullptr); } template Data BST::DataNDelete(struct BST::NodeLnk* ptr){ Data data = ptr->Element(); delete ptr; return data; } template typename BST::NodeLnk* BST::Detach(struct BST::NodeLnk*& ptrref) noexcept{ if(ptrref == nullptr) return nullptr; if(ptrref->left == nullptr){ return SkipOnRight(ptrref); } else if(ptrref->right == nullptr){ return SkipOnLeft(ptrref); } else{ NodeLnk* maxNode = DetachMax(ptrref->left); std::swap(ptrref->Element() , maxNode->Element()); return maxNode; } } template typename BST::NodeLnk* BST::DetachMin(struct BST::NodeLnk*& ptrref) noexcept{ return SkipOnRight(FindPointerToMin(ptrref)); } template typename BST::NodeLnk* BST::DetachMax(struct BST::NodeLnk*& ptrref) noexcept{ return SkipOnLeft(FindPointerToMax(ptrref)); } template typename BST::NodeLnk* BST::SkipOnLeft(struct BST::NodeLnk*& ptrref) noexcept{ NodeLnk* left = nullptr; if(ptrref != nullptr){ std::swap(left, ptrref->left); std::swap(left, ptrref); --size; } return left; } template typename BST::NodeLnk* BST::SkipOnRight(struct BST::NodeLnk*& ptrref) noexcept{ NodeLnk* right = nullptr; if(ptrref != nullptr){ std::swap(right, ptrref->right); std::swap(right, ptrref); --size; } return right; } template typename BST::NodeLnk* const& BST::FindPointerToMin(struct BST::NodeLnk* const& node) const noexcept{ /* In order to return a [reference to a] const pointer, we need to declare a variable (ptr) which points to a const pointer which points to a NodeLnk. This const pointer that points to a NodeLnk is the parameter of the function. Hence, *ptr will be a const pointer. */ NodeLnk* const* ptr = &node; NodeLnk* curr = node; if(curr!=nullptr){ while(curr->left != nullptr){ ptr = &curr->left; curr = curr->left; } } return *ptr; } template typename BST::NodeLnk*& BST::FindPointerToMin(struct BST::NodeLnk*& node) noexcept{ return const_cast(static_cast *>(this)->FindPointerToMin(node)); } template typename BST::NodeLnk* const& BST::FindPointerToMax(struct BST::NodeLnk* const& node) const noexcept{ NodeLnk* const* ptr = &node; NodeLnk* curr = node; if(curr!=nullptr){ while(curr->right != nullptr){ ptr = &curr->right; curr = curr->right; } } return *ptr; } template typename BST::NodeLnk*& BST::FindPointerToMax(struct BST::NodeLnk*& node) noexcept{ return const_cast(static_cast *>(this)->FindPointerToMax(node)); } template typename BST::NodeLnk* const& BST::FindPointerTo(struct BST::NodeLnk* const& ref, Data data) const noexcept{ /* In order to return a [reference to a] const pointer, we need to declare a variable (pointer) which points to a const pointer which points to a NodeLnk. This const pointer that points to a NodeLnk is the parameter of the function. Hence, (*pointer) will be a const pointer. Note: this function (and others too) could've been written using one single pointer, in this way: while(*pointer != nullptr && (*(*pointer)).Element() != data){ if( (*(*pointer)).Element() < data ) pointer = &((*pointer)->right); else if((*(*pointer)).Element() > data ) pointer = &((*pointer)->left); } but I preferred to use a clearer version. */ NodeLnk* const* pointer = &ref; //a pointer to a const pointer to a NodeLnk NodeLnk* current = ref; while(current != nullptr && current->Element() != data){ if(current->Element() < data){ pointer = &(current->right); current = current->right; }else if(current->Element() > data){ pointer = &(current->left); current = current->left; } } return *pointer; } template typename BST::NodeLnk* const* BST::FindPointerToPredecessor(struct BST::NodeLnk* const& ref, Data data) const noexcept{ /* If the element we are looking the predecessor for is the current element, then its predecessor resides in the max node of its left subtree (if it has a left subtree. Return the candidate otherwise). If the element we are looking the predecessor for is greater than the current element, then we have to go down right the tree, saving the current "candidate". If the element we are looking the predecessor for is less than the current element, then we have to go down left the tree. */ NodeLnk* const* pointer = &ref; NodeLnk* current = ref; NodeLnk* const* candidate = nullptr; while(current != nullptr){ if(data == current->Element()){ if(current->HasLeftChild()){ return &(FindPointerToMax(current->left)); }else{ return candidate; } }else if(current->Element() < data){ candidate = pointer; pointer = &(current->right); current = current->right; }else if(current->Element() > data){ pointer = &(current->left); current = current->left; } } return candidate; } template typename BST::NodeLnk* const* BST::FindPointerToSuccessor(struct BST::NodeLnk* const& ref, Data data) const noexcept{ NodeLnk* const* pointer = &ref; NodeLnk* current = ref; NodeLnk* const* candidate = nullptr; while( current != nullptr){ if(data == current->Element()){ if(current->HasRightChild()){ return &(FindPointerToMin(current->right)); } else{ return candidate; } }else if(current->Element() > data){ candidate = pointer; pointer = ¤t->left; current = current->left; }else if(current->Element() < data){ pointer = ¤t->right; current = current->right; } } return candidate; } template typename BST::NodeLnk*& BST::FindPointerTo(struct BST::NodeLnk*& node, Data data) noexcept{ return const_cast(static_cast *>(this)->FindPointerTo(node, data)); } template typename BST::NodeLnk** BST::FindPointerToPredecessor(struct BST::NodeLnk*& node, Data data) noexcept{ return const_cast(static_cast *>(this)->FindPointerToPredecessor(node, data)); } template typename BST::NodeLnk** BST::FindPointerToSuccessor(struct BST::NodeLnk*& node, Data data) noexcept{ return const_cast(static_cast *>(this)->FindPointerToSuccessor(node, data)); } }