Compare commits

...

2 Commits

Author SHA1 Message Date
8e55246e9c
8.8 Lab: BT <--- BST (Smallest/Largest)
The assignment consists of the following classes/files:

- BinaryNode.h (template, given)
- BinaryTree.h (template, incomplete)
- BinarySearchTree.h(template, incomplete)
- main.cpp (incomplete)

Write the following functions:

- findSmallest (recursive)
- findLargest (recursive)
2024-05-03 13:15:46 -07:00
2ff40ef4e9
8.7 Lab: BT <--- BST (Traversals) 2024-05-03 13:02:04 -07:00
7 changed files with 344 additions and 267 deletions

46
05-trees/BinaryNode.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef _BINARY_NODE
#define _BINARY_NODE
template<class ItemType>
class BinaryNode {
private:
ItemType item; // Data portion
BinaryNode<ItemType> *leftPtr; // Pointer to left child
BinaryNode<ItemType> *rightPtr; // Pointer to right child
public:
// constructors
BinaryNode(const ItemType &anItem) {
item = anItem;
leftPtr = 0;
rightPtr = 0;
}
BinaryNode(const ItemType &anItem,
BinaryNode<ItemType> *left,
BinaryNode<ItemType> *right) {
item = anItem;
leftPtr = left;
rightPtr = right;
}
// setters
void setItem(const ItemType &anItem) { item = anItem; }
void setLeftPtr(BinaryNode<ItemType> *left) { leftPtr = left; }
void setRightPtr(BinaryNode<ItemType> *right) { rightPtr = right; }
// getters
ItemType getItem() const { return item; }
BinaryNode<ItemType> *getLeftPtr() const { return leftPtr; }
BinaryNode<ItemType> *getRightPtr() const { return rightPtr; }
// other functions
bool isLeaf() const { return (leftPtr == 0 && rightPtr == 0); }
};
#endif

127
05-trees/BinarySearchTree.h Normal file
View File

@ -0,0 +1,127 @@
// 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 ItemType>
class BinarySearchTree : public BinaryTree<ItemType> {
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<ItemType> *_insert(BinaryNode<ItemType> *nodePtr, BinaryNode<ItemType> *newNode);
// search for target node
//BinaryNode<ItemType>* _search(BinaryNode<ItemType>* treePtr, const ItemType &target) const;
// find the smallest node
BinaryNode<ItemType> *_findSmallest(BinaryNode<ItemType> *nodePtr, ItemType &smallest) const;
// find the biggest node
BinaryNode<ItemType> *_findLargest(BinaryNode<ItemType> *nodePtr, ItemType &smallest) const;
// internal remove node: locate and delete target node under nodePtr subtree
// BinaryNode<ItemType>* _remove(BinaryNode<ItemType>* nodePtr, const ItemType target, bool &success);
// delete target node from tree, called by internal remove node
// BinaryNode<ItemType>* _removeNode(BinaryNode<ItemType>* targetNodePtr);
// remove the leftmost node in the left subtree of nodePtr
// BinaryNode<ItemType>* _removeLeftmostNode(BinaryNode<ItemType>* nodePtr, ItemType &successor);
};
///////////////////////// public function definitions ///////////////////////////
// Inserting items within a tree
template<class ItemType>
bool BinarySearchTree<ItemType>::insert(const ItemType &newEntry) {
BinaryNode<ItemType> *newNodePtr = new BinaryNode<ItemType>(newEntry);
this->rootPtr = _insert(this->rootPtr, newNodePtr);
return true;
}
// Finding the smallest, which is the leftmost leaf (wrapper function)
template<class ItemType>
bool BinarySearchTree<ItemType>::findSmallest(ItemType &returnedItem) const {
BinaryNode<ItemType> *temp = nullptr;
temp = _findSmallest(this->rootPtr, returnedItem);
return temp != nullptr;
}
// Finding the biggest, which is the rightmost leaf (wrapper function)
template<class ItemType>
bool BinarySearchTree<ItemType>::findLargest(ItemType &returnedItem) const {
BinaryNode<ItemType> *temp = nullptr;
temp = _findLargest(this->rootPtr, returnedItem);
return temp != nullptr;
}
//////////////////////////// private functions ////////////////////////////////////////////
// Implementation of the insert operation - iterative algorithm
template<class ItemType>
BinaryNode<ItemType> *BinarySearchTree<ItemType>::_insert(BinaryNode<ItemType> *nodePtr,
BinaryNode<ItemType> *newNodePtr) {
BinaryNode<ItemType> *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;
}
// Implementation to find the smallest: recursive
template<class ItemType>
BinaryNode<ItemType> *
BinarySearchTree<ItemType>::_findSmallest(BinaryNode<ItemType> *nodePtr, ItemType &smallest) const {
if (nodePtr->getLeftPtr() == nullptr) {
smallest = nodePtr->getItem();
return nodePtr;
}
return _findSmallest(nodePtr->getLeftPtr(), smallest);
}
// Implementation to find the largest: recursive
template<class ItemType>
BinaryNode<ItemType> *BinarySearchTree<ItemType>::_findLargest(BinaryNode<ItemType> *nodePtr, ItemType &biggest) const {
if (nodePtr->getRightPtr() == nullptr) {
biggest = nodePtr->getItem();
return nodePtr;
}
return _findLargest(nodePtr->getRightPtr(), biggest);
}
#endif

View File

@ -1,145 +0,0 @@
// Implementation file for the BinaryTree class
#include <iostream> // For cout and NULL
#include "BinaryTree.h"
#include <cstdlib> // For rand()
#include <ctime> // 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;
}
}

View File

@ -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 ItemType>
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<ItemType> *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<ItemType> &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<ItemType> *nodePtr);
void _preOrder(Node *root, void visit(const Data &)) const;
// internal traverse
void _preorder(void visit(ItemType &), BinaryNode<ItemType> *nodePtr) const;
void _postOrder(Node *root, void visit(const Data &)) const;
void _inorder(void visit(ItemType &), BinaryNode<ItemType> *nodePtr) const;
void _postorder(void visit(ItemType &), BinaryNode<ItemType> *nodePtr) const;
// void _printTree(void visit(ItemType &, int), BinaryNode<ItemType>* nodePtr, int level) const;
void _destroy(Node *root);
};
// Destroy the entire tree
template<class ItemType>
void BinaryTree<ItemType>::destroyTree(BinaryNode<ItemType> *nodePtr) {
if (nodePtr) // != NULL
{
destroyTree(nodePtr->getLeftPtr());
destroyTree(nodePtr->getRightPtr());
// cout << "DEBUG - Destructor: Now deleting " << nodePtr->getItem().getName() << endl;
delete nodePtr;
}
}
// Preorder Traversal
template<class ItemType>
void BinaryTree<ItemType>::_preorder(void visit(ItemType &), BinaryNode<ItemType> *nodePtr) const {
if (nodePtr == nullptr) return;
ItemType item = nodePtr->getItem();
visit(item);
_preorder(visit, nodePtr->getLeftPtr());
_preorder(visit, nodePtr->getRightPtr());
}
// Inorder Traversal
template<class ItemType>
void BinaryTree<ItemType>::_inorder(void visit(ItemType &), BinaryNode<ItemType> *nodePtr) const {
if (nodePtr) // != NULL
{
ItemType item = nodePtr->getItem();
_inorder(visit, nodePtr->getLeftPtr());
visit(item);
_inorder(visit, nodePtr->getRightPtr());
}
}
// Postorder Traversal
template<class ItemType>
void BinaryTree<ItemType>::_postorder(void visit(ItemType &), BinaryNode<ItemType> *nodePtr) const {
if (nodePtr == nullptr) return;
_postorder(visit, nodePtr->getLeftPtr());
_postorder(visit, nodePtr->getRightPtr());
ItemType item = nodePtr->getItem();
visit(item);
}
#endif

View File

@ -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 <iostream>
#include <fstream>
#include <cstdlib>
#include <cstdlib>
#include <ctime>
#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;
}

View File

@ -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)

74
05-trees/main.cpp Normal file
View File

@ -0,0 +1,74 @@
// BST ADT
// Smallest/Largest
// Name: Iurii Tatishchev
#include "BinarySearchTree.h"
#include <iostream>
#include <string>
using namespace std;
void buildBST(int n, BinarySearchTree<int> &);
void hDisplay(int &);
void vDisplay(int &);
int main() {
BinarySearchTree<int> bst;
int n;
char option;
cout << "What is the number of nodes in the BST? " << endl;
cin >> n;
cout << "Find Smallest or Largest[S/L]? " << endl;
cin >> option;
buildBST(n, bst);
if (n < 15) {
cout << " Inorder: ";
bst.inOrder(hDisplay);
cout << endl;
}
if (option == 'S' || option == 's') {
int minVal;
bst.findSmallest(minVal);
cout << "Smallest: " << minVal << endl;
} else if (option == 'L' || option == 'l') {
int maxVal;
bst.findLargest(maxVal);
cout << "Largest: " << maxVal << endl;
}
return 0;
}
/*
buildBST: builds a binary search tree
of integers
*/
void buildBST(int n, BinarySearchTree<int> &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;
}