From 2ff40ef4e9cb15b140458e2d6b5eaf2fe7298077 Mon Sep 17 00:00:00 2001 From: Iurii Tatishchev Date: Fri, 3 May 2024 13:02:04 -0700 Subject: [PATCH] 8.7 Lab: BT <--- BST (Traversals) --- 05-trees/BinaryNode.h | 46 +++++++++++ 05-trees/BinarySearchTree.h | 90 ++++++++++++++++++++++ 05-trees/BinaryTree.cpp | 145 ----------------------------------- 05-trees/BinaryTree.h | 122 ++++++++++++++++++++++------- 05-trees/BinaryTree_Demo.cpp | 90 ---------------------- 05-trees/CMakeLists.txt | 7 +- 05-trees/main.cpp | 74 ++++++++++++++++++ 7 files changed, 307 insertions(+), 267 deletions(-) create mode 100644 05-trees/BinaryNode.h create mode 100644 05-trees/BinarySearchTree.h delete mode 100644 05-trees/BinaryTree.cpp delete mode 100644 05-trees/BinaryTree_Demo.cpp create mode 100644 05-trees/main.cpp diff --git a/05-trees/BinaryNode.h b/05-trees/BinaryNode.h new file mode 100644 index 0000000..123e84f --- /dev/null +++ b/05-trees/BinaryNode.h @@ -0,0 +1,46 @@ +#ifndef _BINARY_NODE +#define _BINARY_NODE + +template +class BinaryNode { +private: + ItemType item; // Data portion + BinaryNode *leftPtr; // Pointer to left child + BinaryNode *rightPtr; // Pointer to right child + +public: + // constructors + BinaryNode(const ItemType &anItem) { + item = anItem; + leftPtr = 0; + rightPtr = 0; + } + + BinaryNode(const ItemType &anItem, + BinaryNode *left, + BinaryNode *right) { + item = anItem; + leftPtr = left; + rightPtr = right; + } + + // setters + void setItem(const ItemType &anItem) { item = anItem; } + + void setLeftPtr(BinaryNode *left) { leftPtr = left; } + + void setRightPtr(BinaryNode *right) { rightPtr = right; } + + // getters + ItemType getItem() const { return item; } + + BinaryNode *getLeftPtr() const { return leftPtr; } + + BinaryNode *getRightPtr() const { return rightPtr; } + + // other functions + bool isLeaf() const { return (leftPtr == 0 && rightPtr == 0); } + +}; + +#endif diff --git a/05-trees/BinarySearchTree.h b/05-trees/BinarySearchTree.h new file mode 100644 index 0000000..75a9477 --- /dev/null +++ b/05-trees/BinarySearchTree.h @@ -0,0 +1,90 @@ +// Binary Search Tree ADT +// Created by Iurii Tatishchev +// Modified by: Iurii Tatishchev + +#ifndef _BINARY_SEARCH_TREE +#define _BINARY_SEARCH_TREE + +#include "BinaryTree.h" + +template +class BinarySearchTree : public BinaryTree { +public: + // insert a node at the correct location + bool insert(const ItemType &item); + // remove a node if found + //bool remove(const ItemType &item); + // find a target node + //bool search(const ItemType &target, ItemType &returnedItem) const; + // find the smallest node + //bool findSmallest(ItemType &returnedItem) const; + // find the largest node + //bool findLargest(ItemType &returnedItem) const; + +private: + // internal insert node: insert newNode in nodePtr subtree + BinaryNode *_insert(BinaryNode *nodePtr, BinaryNode *newNode); + + // search for target node + //BinaryNode* _search(BinaryNode* treePtr, const ItemType &target) const; + + // find the smallest node + //BinaryNode* _findSmallest(BinaryNode* nodePtr, ItemType &smallest) const; + + // find the biggest node + //BinaryNode* _findLargest(BinaryNode* nodePtr, ItemType &smallest) const; + + // internal remove node: locate and delete target node under nodePtr subtree + // BinaryNode* _remove(BinaryNode* nodePtr, const ItemType target, bool &success); + + // delete target node from tree, called by internal remove node + //BinaryNode* _removeNode(BinaryNode* targetNodePtr); + + // remove the leftmost node in the left subtree of nodePtr + //BinaryNode* _removeLeftmostNode(BinaryNode* nodePtr, ItemType &successor); + +}; + + +///////////////////////// public function definitions /////////////////////////// +//Inserting items within a tree +template +bool BinarySearchTree::insert(const ItemType &newEntry) { + BinaryNode *newNodePtr = new BinaryNode(newEntry); + this->rootPtr = _insert(this->rootPtr, newNodePtr); + return true; +} + + + +//////////////////////////// private functions //////////////////////////////////////////// + +//Implementation of the insert operation +template +BinaryNode *BinarySearchTree::_insert(BinaryNode *nodePtr, + BinaryNode *newNodePtr) { + BinaryNode *pWalk = nodePtr, *parent = nullptr; + + if (!nodePtr) // == NULL + { + nodePtr = newNodePtr; + return nodePtr; + } else { + while (pWalk) // != NULL + { + parent = pWalk; + if (pWalk->getItem() > newNodePtr->getItem()) + pWalk = pWalk->getLeftPtr(); + else + pWalk = pWalk->getRightPtr(); + } + if (parent->getItem() > newNodePtr->getItem()) + parent->setLeftPtr(newNodePtr); + else + parent->setRightPtr(newNodePtr); + } + + return nodePtr; +} + +#endif diff --git a/05-trees/BinaryTree.cpp b/05-trees/BinaryTree.cpp deleted file mode 100644 index 3275a0f..0000000 --- a/05-trees/BinaryTree.cpp +++ /dev/null @@ -1,145 +0,0 @@ -// Implementation file for the BinaryTree class -#include // For cout and NULL - - -#include "BinaryTree.h" -#include // For rand() -#include // For time() - -using namespace std; - -/**~*~* - Constructor -*~**/ -BinaryTree::BinaryTree() { - root = NULL; - count = 0; -} - -/**~*~* - This function calls a recursive function to traverse the - tree in postorder -*~**/ -void BinaryTree::postOrder(void visit(const Data &)) const { - _postOrder(root, visit); -} - -/**~*~* - Postorder Traversal of the Binary Tree: - Left-Right-Root -*~**/ -void BinaryTree::_postOrder(BinaryTree::Node *root, void visit(const Data &)) const { - if (root == nullptr) return; - - _postOrder(root->left, visit); - _postOrder(root->right, visit); - visit(root->data); -} - -/**~*~* - This function calls a recursive function to traverse the - tree in preorder -*~**/ -void BinaryTree::preOrder(void visit(const Data &)) const { - _preOrder(root, visit); -} - -/**~*~* - Postorder Traversal of the Binary Tree: - Left-Right-Root -*~**/ -void BinaryTree::_preOrder(BinaryTree::Node *root, void visit(const Data &)) const { - if (root == nullptr) return; - - visit(root->data); - _preOrder(root->left, visit); - _preOrder(root->right, visit); -} - -/**~*~* - This function calls a recursive function to traverse the - tree in inorder -*~**/ -void BinaryTree::inOrder(void visit(const Data &)) const { - _inOrder(root, visit); -} - -/**~*~* - Inorder Traversal of the Binary Tree: - Left-Root-Right -*~**/ -void BinaryTree::_inOrder(Node *root, void visit(const Data &)) const { - if (root) { - _inOrder(root->left, visit); - //cout << root->data.num << " "; - visit(root->data); - // cout has been replaced with a call for visit - // What is visit? - // visit is a generic name for a display function - // in main(), when inOrder is called, it is decided what function address to assign to visit - // here, you just use visit the way you would use/call a function - _inOrder(root->right, visit); - // ------------------^^^^^^ visit as an argument - } -} - -/**~*~* - Insert data into a random Binary Tree -*~**/ -void BinaryTree::insert(Data dataIn) { - Node *newNode; - Node *pWalk; - Node *parent; - int rand_num; - - // allocate the new node - newNode = new Node; - newNode->data = dataIn; - newNode->left = NULL; - newNode->right = NULL; - - // find a "random" parent - if (!root) // tree is empty - root = newNode; - else { - parent = NULL; // root does not have a parent - pWalk = root; - while (pWalk) { - parent = pWalk; - rand_num = rand() % 100; - if (rand_num % 2) // if odd - take left - pWalk = pWalk->left; - else - pWalk = pWalk->right; - } - - // insert the new node - if (!parent->left) // no left child - parent->left = newNode; - else - parent->right = newNode; - } - - count++; -} - - -/**~*~* - Destructor - This function calls a recursive function to delete all nodes in the binary tree -*~**/ -BinaryTree::~BinaryTree() { - if (root) - _destroy(root); -} - -/**~*~* - This function traverses the binary tree in postorder and deletes every node -*~**/ -void BinaryTree::_destroy(Node *root) { - if (root) { - _destroy(root->left); - _destroy(root->right); - delete root; - } -} diff --git a/05-trees/BinaryTree.h b/05-trees/BinaryTree.h index 1d7520d..8cefc92 100644 --- a/05-trees/BinaryTree.h +++ b/05-trees/BinaryTree.h @@ -1,47 +1,111 @@ -// Specification file for the BinaryTree class -#ifndef BINARY_TREE_H -#define BINARY_TREE_H +// Binary tree abstract base class +// Created by Iurii Tatishchev +// Modified by: Iurii Tatishchev -struct Data { - int num; - // more fields could be added if needed -}; +#ifndef _BINARY_TREE +#define _BINARY_TREE +#include "BinaryNode.h" + +template class BinaryTree { -private: - struct Node { - Data data; // The value in this node - Node *left; // To point to the left node - Node *right; // To point to the right node - }; - - Node *root; // root of the tree - int count; // number of nodes in the tree +protected: + BinaryNode *rootPtr; // ptr to root node + int count; // number of nodes in tree public: - // Constructor - BinaryTree(); + // "admin" functions + BinaryTree() { + rootPtr = nullptr; + count = 0; + } - // Destructor - ~BinaryTree(); + BinaryTree(const BinaryTree &tree) {} - // Binary Tree operations - void insert(Data dataIn); + virtual ~BinaryTree() { destroyTree(rootPtr); } - void inOrder(void visit(const Data &)) const; + // common functions for all binary trees + bool isEmpty() const { return count == 0; } - void preOrder(void visit(const Data &)) const; + int getCount() const { return count; } - void postOrder(void visit(const Data &)) const; + void clear() { + destroyTree(rootPtr); + rootPtr = nullptr; + count = 0; + } + + void preOrder(void visit(ItemType &)) const { _preorder(visit, rootPtr); } + + void inOrder(void visit(ItemType &)) const { _inorder(visit, rootPtr); } + + void postOrder(void visit(ItemType &)) const { _postorder(visit, rootPtr); } + // void printTree(void visit(ItemType &, int)) const{_printTree(visit, rootPtr, 1);} + + // abstract functions to be implemented by derived class + virtual bool insert(const ItemType &newData) = 0; + //virtual bool remove(const ItemType &data) = 0; + //virtual bool search(const ItemType &target, ItemType & returnedItem) const = 0; private: - void _inOrder(Node *root, void visit(const Data &)) const; + // delete all nodes from the tree + void destroyTree(BinaryNode *nodePtr); - void _preOrder(Node *root, void visit(const Data &)) const; + // internal traverse + void _preorder(void visit(ItemType &), BinaryNode *nodePtr) const; - void _postOrder(Node *root, void visit(const Data &)) const; + void _inorder(void visit(ItemType &), BinaryNode *nodePtr) const; + + void _postorder(void visit(ItemType &), BinaryNode *nodePtr) const; + // void _printTree(void visit(ItemType &, int), BinaryNode* nodePtr, int level) const; - void _destroy(Node *root); }; +// Destroy the entire tree +template +void BinaryTree::destroyTree(BinaryNode *nodePtr) { + if (nodePtr) // != NULL + { + destroyTree(nodePtr->getLeftPtr()); + destroyTree(nodePtr->getRightPtr()); + // cout << "DEBUG - Destructor: Now deleting " << nodePtr->getItem().getName() << endl; + delete nodePtr; + } +} + +// Preorder Traversal +template +void BinaryTree::_preorder(void visit(ItemType &), BinaryNode *nodePtr) const { + if (nodePtr == nullptr) return; + + ItemType item = nodePtr->getItem(); + visit(item); + _preorder(visit, nodePtr->getLeftPtr()); + _preorder(visit, nodePtr->getRightPtr()); + +} + +// Inorder Traversal +template +void BinaryTree::_inorder(void visit(ItemType &), BinaryNode *nodePtr) const { + if (nodePtr) // != NULL + { + ItemType item = nodePtr->getItem(); + _inorder(visit, nodePtr->getLeftPtr()); + visit(item); + _inorder(visit, nodePtr->getRightPtr()); + } +} + +// Postorder Traversal +template +void BinaryTree::_postorder(void visit(ItemType &), BinaryNode *nodePtr) const { + if (nodePtr == nullptr) return; + + _postorder(visit, nodePtr->getLeftPtr()); + _postorder(visit, nodePtr->getRightPtr()); + ItemType item = nodePtr->getItem(); + visit(item); +} + #endif diff --git a/05-trees/BinaryTree_Demo.cpp b/05-trees/BinaryTree_Demo.cpp deleted file mode 100644 index 75f0527..0000000 --- a/05-trees/BinaryTree_Demo.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/** - - Test Driver for Binary Tree functions - - This program builds a BT of random integers - - Note: The BT_insert() function is specific to this exercise - - The main goal of this example is build a binary tree that could be used to - test the traversal and other binary tree functions - -*/ - -#include -#include -#include -#include -#include -#include "BinaryTree.h" - -using namespace std; - -void build_BT(BinaryTree &tree, int n); - -void hDisplay(const Data &item); // horizontal display: all items on one line -void vDisplay(const Data &item); // vertical display: one item per line - -int main(void) { - BinaryTree tree; - int n; // number of nodes - char option; - cout << "What is the number of nodes in the BT? " << endl; - cin >> n; - cout << "What traversal[prE/posT]? " << endl; - cin >> option; - - build_BT(tree, n); - - cout << " Inorder: "; - tree.inOrder(hDisplay); // hDisplay is the inOrder's argument - cout << endl; - - if (option == 'T' || option == 't') { - cout << "Postorder: "; - tree.postOrder(hDisplay); // passing hDisplay to postOrder - cout << endl; - tree.postOrder(vDisplay); // passing vDisplay to postOrder - cout << endl; - } - if (option == 'E' || option == 'e') { - cout << " Preorder: "; - tree.preOrder(hDisplay); // passing hDisplay to preOrder - cout << endl; - tree.preOrder(vDisplay); // passing vDisplay to preOrder - cout << endl; - } - return 0; -} - -/**~*~* - Builds a random Binary Tree of integer numbers within the range - [10, 99]; root is always 50 -*/ -void build_BT(BinaryTree &tree, int n) { - Data data = {50}; - - // allocate and initialize the root - tree.insert(data); - - //srand((unsigned int)time(0)); - while (--n) { - data.num = rand() % 90 + 10; - tree.insert(data); - } -} - -// The following two functions are used as arguments to other functions -/**~*~* - horizontal display: all items on one line -*/ -void hDisplay(const Data &item) { - cout << item.num << " "; -} - -/**~*~* - // vertical display: one item per line -*/ -void vDisplay(const Data &item) { - cout << item.num << endl; -} diff --git a/05-trees/CMakeLists.txt b/05-trees/CMakeLists.txt index bb0cbb1..c5e6975 100644 --- a/05-trees/CMakeLists.txt +++ b/05-trees/CMakeLists.txt @@ -3,6 +3,7 @@ project(05_trees) set(CMAKE_CXX_STANDARD 20) -add_executable(05_trees BinaryTree_Demo.cpp - BinaryTree.cpp - BinaryTree.h) +add_executable(05_trees main.cpp + BinaryTree.h + BinaryNode.h + BinarySearchTree.h) diff --git a/05-trees/main.cpp b/05-trees/main.cpp new file mode 100644 index 0000000..5f77e4c --- /dev/null +++ b/05-trees/main.cpp @@ -0,0 +1,74 @@ +// BST ADT - Traversals +// Name: Iurii Tatishchev +#include "BinarySearchTree.h" +#include +#include + +using namespace std; + +void buildBST(int n, BinarySearchTree &); + +void hDisplay(int &); + +void vDisplay(int &); + + +int main() { + BinarySearchTree bst; + + int n; + char option; + + cout << "What is the number of nodes in the BST? " << endl; + cin >> n; + cout << "What traversal[prE/posT]? " << endl; + cin >> option; + + buildBST(n, bst); + + cout << " Inorder: "; + bst.inOrder(hDisplay); // pass hDisplay to inOrder + cout << endl; + if (option == 'T' || option == 't') { + cout << "Postorder: "; + bst.postOrder(hDisplay); // pass hDisplay to postOrder + cout << endl; + bst.postOrder(vDisplay); // pass vDisplay to postOrder + cout << endl; + } else if (option == 'E' || option == 'e') { + cout << " Preorder: "; + bst.preOrder(hDisplay); // pass hDisplay to preOrder + cout << endl; + bst.preOrder(vDisplay); // pass vDisplay to preOrder + cout << endl; + } + + return 0; +} + +/* + buildBST: builds a binary search tree + of integers +*/ +void buildBST(int n, BinarySearchTree &bst) { + int item; + + while (n--) { + item = rand() % 30 + 10; + bst.insert(item); + } +} + +/* + horizontal display: all items on one line +*/ +void hDisplay(int &item) { + cout << item << " "; +} + +/* + vertical display: one item per line +*/ +void vDisplay(int &item) { + cout << item << endl; +}