Binary Search Tree Pt1

Video

There is an interactive demo here you will create a Binary Search Tree copy over the files created for you there is a main, Makefile, BST.h, examples and testfiles Binary Search Tree =============================================== i Insert a value into the tree p Print the values of the tree in sorted order m Show this menu x Exit =============================================== Enter selection: the output when testing should match that of the runable examples MAKE sure you output matches the examples when you redirect in the testfiles MAKE sure your ToString output can be used on the viewtree page the output of your print MUST work with the viewtree page you will complete the function bodies in File: BST.h

#pragma once
#include "cmpslib19.h"
#include "easylogging++.h"


template <class T>
class BST
{
	class TreeNode
	{
		public:
			T data;
			TreeNode *left;
			TreeNode *right;
			TreeNode(T val)
			{
				data=val;
				left=nullptr;
				right=nullptr;
			}
	};

	private:
	TreeNode *root;

	// private helper function for insert. It will see if the value belongs in the left or
	// right subtree. If the correct subtree is currently nullptr , it will allocate a
	// new node and insert it there. Otherwise, it will recursively call
	// insertSubtree on that subtree.
	// return type bool, was the insert successful
	bool insertSubtree(TreeNode * subtree, T elem)
	{
		// if this node already has the value in it that we want to store
		// return false
		// if the value to insert is greater than the value in the current node
		// go down the right side.. if the right pointer is nullptr add
		// the new node there, if its not nullptr then call insertSubtree
		// with the right pointer
		// if the value to insert is less than the value in the current node ( else ) 
		// use the same logic for the left side
	}

	// private helper function for in-order print traversal. Performs an in-order print
	// traversal by recursively calling inorderSubtree on the left subtree, then
	// printing the data in the current node, then recursively calling
	// inorderSubtree on the right subtree.
	// return type void
	void printSubtree(TreeNode * subtree)
	{
		// if the left node pointer is not nullptr recursively call printSubtree on left
		// print the values from this node
		// if the right node pointer is not nullptr recursively call printSubtree on right
	}

	// a private helper function to remove nodes
	// search down the tree starting at the node provided and if the value is found
	// delete that node
	// parameters:
	// a pointer to a node in the tree
	// a value ( the value to be removed )
	// return type bool
	bool remove(TreeNode* ptr, T elem)
	{
		LOG(INFO) << "Start " <<  __PRETTY_FUNCTION__ << endl;
		TreeNode* parent = ptr;      // parent of node to delete

		/*
			 Try to find the element in the tree
			 keep moving down the tree to we reach a nullptr pointer or find the value
			 use two pointers as you must have a pointer to the parrent Node of the one you
			 need to delete in order to proceed
		 */
		while (true)
		{
			if (ptr == nullptr)
			{
				// bottom of the tree  and we did not find it
				LOG(INFO) << "End " <<  __PRETTY_FUNCTION__ << endl;
				LOG(INFO) << "Returning: false" << endl;
				return(false);
			}
			if (ptr->data == elem)
			{
				break;  // found it stop while loop
			}
			if (elem < ptr->data)
			{
				// the value we are looking for is less so go left
				parent = ptr;
				ptr = ptr->left;
			}
			else
			{
				// the value we are looking for is more so go right
				parent = ptr;
				ptr = ptr->right;
			}
		}

		// at this point ptr should point to the node we want to delete
		// and parent should point to the node above it (if if is not the root node)

		/* there are really 3 possible scenarios
			 1 the node we want to delete has no chilren , easy
			 2 the node we wnat to delte has 1 child , not bad
			 3 the node we wand to delete has 2 children, most involved */

		// case 1 , no children
		if (ptr->right == nullptr && ptr->left == nullptr)
		{
			LOG (INFO) <<"Case 1 , no child nodes\n";
			// set the ponter in parrent that curently points to the node we want to delete to nullptr
			if(parent->right==ptr)
			{
				parent->right=nullptr;
			}
			else
			{
				parent->left=nullptr;
			}
			LOG (INFO) << "deleting a node containing " << ptr->data << endl;
			if (ptr == root )
			{
				root = nullptr;
			}
			delete ptr;
			LOG(INFO) << "End " <<  __PRETTY_FUNCTION__ << endl;
			LOG(INFO) << "Returning: true" << endl;
			return true;
		} // end case 1

		// case 2 , one child node
		if ( ptr->right == nullptr || ptr->left == nullptr) // one is null so there is only one child node
		{
			LOG (INFO) << "Case 2 , one child node\n";
			// set the pointer in the parrent of ptr to point to the child of ptr, so we can delete the node tmp
			((parent->right == ptr) ? parent->right : parent->left ) =  ( (ptr->right != nullptr) ?  ptr->right: ptr->left);

			// if ptr is the root node we better update the pointer root so it isnt still pointing the node we are going to delete
			if  (root == ptr)
			{
				root  =  ( (ptr->right != nullptr) ?  ptr->right: ptr->left);
			}
			LOG (INFO) << "deleting a node containing " << ptr->data << endl;
			delete ptr;
			LOG(INFO) << "End " <<  __PRETTY_FUNCTION__ << endl;
			LOG(INFO) << "Returning: true" << endl;
			return true;
		} // endl case 2

		// case 3 is all that is left
		// Two children to this node, need to find replacement node using either
		// inorder successor or inorder predecessor.

		// Inorder precessor is the largest value in the left subtree
		TreeNode* replacement = ptr->left;
		while(replacement->right)
		{
			replacement = replacement->right;
		}

		// copy the data up to the node we were originally wanting to delete
		T temp = replacement->data;
		LOG (INFO) << "Calling remove for a node with a value of " << temp << " but we are atually going to put the value " << temp 
							<< " into the node that use to have the value "  << ptr->data << endl;
		remove(ptr,temp);
		ptr->data = temp;
		LOG(INFO) << "End " <<  __PRETTY_FUNCTION__ << endl;
			LOG(INFO) << "Returning: true" << endl;
		return true;
	}


	public:
	BST()
	{
		// set the pointer to the root node to nullptr
	}

	bool empty()
	{
		//if the root node equals the nullptr the tree is empty
		LOG(INFO) << "Start " <<  __PRETTY_FUNCTION__ << endl;
		LOG(INFO) << "End " <<  __PRETTY_FUNCTION__ << endl;
		LOG(INFO) << "Returning: " << boolalpha << (nullptr == root) << endl;
		return (nullptr == root);
	}




	bool insert(T elem)
	{
		// if the root node pointer is nullptr then set the root pointer to a new node
		// store the value to inser into that new node and return true
		// otherwise recursively call insertSubtree
	}



	// Perform an in-order traversal of the tree. This will print all of the tree's
	// values in sorted order.
	void print()
	{
		LOG(INFO) << "Start " <<  __PRETTY_FUNCTION__ << endl;
		// if the root node is not nullptr
		//call printSubtree
		cout << "BST:\nroot:" << root      << endl;
		if (nullptr != root )
		{
			printSubtree(root);
		}
		else
		{
			cout << "No Nodes:\n";
		}

		LOG(INFO) << "End " <<  __PRETTY_FUNCTION__ << endl;
	}

	// public function to remove a value from the tree
	// parameter   value to remove
	// return type bool
	bool remove( T elem)
	{
		LOG(INFO) << "Start " <<  __PRETTY_FUNCTION__ << endl;
		LOG(INFO) << "End " <<  __PRETTY_FUNCTION__ << endl;
		return remove(root,elem);
	}

};