part 3 complete

This commit is contained in:
Christopher Sanden
2025-11-08 14:51:28 +01:00
parent d6d627adad
commit 730987913e
10 changed files with 377 additions and 94 deletions

View File

@@ -10,7 +10,8 @@ add_executable(Assignment-03
TBST.cpp TBST.cpp
TBST.h TBST.h
TEmployee.h TEmployee.h
TTreeQueue.cpp TAVL.cpp
TAVL.h
) )
# Conditionally add the correct source file # Conditionally add the correct source file

View File

@@ -0,0 +1,222 @@
#include "TAVL.h"
#include <ios>
#include <iostream>
#include <unordered_set>
#include <bits/ios_base.h>
#include "TTreeQueue.h"
#include "Utils.h"
// Private helpers
int TAVL::getHeight(const AVLNode *node)
{
return node ? node->height : 0;
}
int TAVL::getBalance(const AVLNode *node)
{
if (!node)
return 0;
return getHeight(node->left) - getHeight(node->right);
}
AVLNode *TAVL::rotateRight(AVLNode *y)
{
if (!y || !y->left)
return y;
AVLNode* x = y->left;
AVLNode* n2 = x ? x->right : nullptr;
x->right = y;
y->left = n2;
x->height = 1 + std::max(getHeight(x->left), getHeight(x->right));
y->height = 1 + std::max(getHeight(y->left), getHeight(y->right));
return x;
}
AVLNode *TAVL::rotateLeft(AVLNode *x)
{
if (!x || !x->right)
return x;
AVLNode* y = x->right;
AVLNode* n2 = y ? y->left : nullptr;
y->left = x;
x->right = n2;
x->height = 1 + std::max(getHeight(x->left), getHeight(x->right));
y->height = 1 + std::max(getHeight(y->left), getHeight(y->right));
return y;
}
// Comment out std::cout lines for no rotation output lines
AVLNode *TAVL::insert(AVLNode *n, const int key)
{
if (!n)
return new AVLNode(key);
if (key < n->key)
n->left = insert(n->left, key);
else if (key > n->key)
n->right = insert(n->right, key);
else
return n; // Ignore duplicates
n->height = 1 + std::max(getHeight(n->left), getHeight(n->right));
const int balance = getBalance(n);
if (balance > 1 && key < n->left->key)
{
std::cout << "L-L rotation on [" << n->key << "]" << std::endl;
return rotateRight(n);
}
if (balance < -1 && key > n->right->key)
{
std::cout << "R-R rotation on [" << n->key << "]" << std::endl;
return rotateLeft(n);
}
if (balance > 1 && key > n->left->key)
{ std::cout << "L-R rotation on [" << n->key << "]" << std::endl;
n->left = rotateLeft(n->left);
return rotateRight(n);
}
if (balance < -1 && key < n->right->key)
{ std::cout << "R-L rotation on [" << n->key << "]" << std::endl;
n->right = rotateRight(n->right);
return rotateLeft(n);
}
return n;
}
void TAVL::preorder(const AVLNode* node)
{
if (!node)
return;
std::cout << "[" << node->key << "] ";
preorder(node->left);
preorder(node->right);
}
void TAVL::inorder(const AVLNode* node)
{
if (!node)
return;
inorder(node->left);
std::cout << "[" << node->key << "] ";
inorder(node->right);
}
void TAVL::postorder(const AVLNode *node)
{
if (!node)
return;
postorder(node->left);
postorder(node->right);
std::cout << "[" << node->key << "] ";
}
void TAVL::levelorder(const AVLNode* node)
{
if (!node)
return;
TTreeQueue<AVLNode> q;
q.Enqueue(const_cast<AVLNode*>(node));
while (!q.IsEmpty()) {
const AVLNode* cur = q.Dequeue();
std::cout << "[" << cur->key << "] ";
if (cur->left)
q.Enqueue(cur->left);
if (cur->right)
q.Enqueue(cur->right);
}
}
// Public functions
void TAVL::Insert(const int key)
{
root = insert(root, key);
}
bool TAVL::Inorder(const AVLNode *node)
{
if (!node)
return true;
inorder(node);
std::cout << std::endl;
return true;
}
bool TAVL::Postorder(const AVLNode *node)
{
if (!node)
return true;
postorder(node);
std::cout << std::endl;
return true;
}
bool TAVL::Preorder(const AVLNode *node)
{
if (!node)
return true;
preorder(node);
std::cout << std::endl;
return true;
}
bool TAVL::LevelOrder(const AVLNode *node)
{
if (!node)
return true;
levelorder(node);
std::cout << std::endl;
return true;
}
void TAVL::PrintOrder(FOrderTraversal cb)
{
if (!cb)
return;
cb(root);
}
///<summary> Populates AVL tree </summary
///<param name="avl"> The AVL tree to be populated</param>
///<param name"count">How many elements to be populated into the tree</param>
///<param name"minRange">Lower bounds of key value range (e.g., the lower limit of element value)</param>
///<param name"maxRange">Upper bounds of key value range (e.g., higher limit og element value)</param>
/// <returns>None</returns>
void TAVL::Populate(TAVL* avl, const int count, const int minRange, const int maxRange)
{
std::unordered_set<int> AVLset;
for (int i = 0; i < count; i++) {
int val = Utils::RandomInt(minRange, maxRange);
while (AVLset.count(val))
val = Utils::RandomInt(minRange, maxRange);
std::cout << "Inserting [" << val << "]" << std::endl;
avl->Insert(val);
AVLset.insert(val);
}
}

View File

@@ -0,0 +1,49 @@
#ifndef IKT203_COURSE_ASSIGNMENTS_TAVL_H
#define IKT203_COURSE_ASSIGNMENTS_TAVL_H
#include <unordered_set>
struct AVLNode {
int key;
AVLNode* left;
AVLNode* right;
int height;
explicit AVLNode(const int k) : key(k), left(nullptr), right(nullptr), height(1) {}
};
typedef bool (*FOrderTraversal)(const AVLNode* AVLNode);
class TAVL {
private:
AVLNode* root;
static int getHeight(const AVLNode* node);
static int getBalance(const AVLNode *node);
static AVLNode* rotateRight(AVLNode* y);
static AVLNode* rotateLeft(AVLNode* x);
static AVLNode* insert(AVLNode* n, int key);
static void inorder(const AVLNode* node);
static void preorder(const AVLNode* node);
static void postorder(const AVLNode* node);
static void levelorder(const AVLNode* node);
public:
TAVL() : root(nullptr) {};
~TAVL() = default;
void Insert(int key);
static bool Inorder(const AVLNode* node);
static bool Postorder(const AVLNode *node);
static bool Preorder(const AVLNode *node);
static bool LevelOrder(const AVLNode *node);
void PrintOrder(FOrderTraversal);
static void Populate(TAVL* AVLtree, int count, int minRange, int maxRange);
};
#endif //IKT203_COURSE_ASSIGNMENTS_TAVL_H

View File

@@ -5,7 +5,7 @@
#include "TTreeQueue.h" #include "TTreeQueue.h"
void TBST::destroy(Node *node) void TBST::destroy(BSTNode *node)
{ {
if (!node) if (!node)
return; return;
@@ -20,10 +20,10 @@ void TBST::Insert(const int key, TEmployee *data)
root = insert(root, key, data); root = insert(root, key, data);
} }
Node* TBST::insert(Node* node, const int key, TEmployee *data) BSTNode* TBST::insert(BSTNode* node, const int key, TEmployee *data)
{ {
if (node == nullptr) { if (node == nullptr) {
auto* n = new Node{key, data, nullptr, nullptr}; auto* n = new BSTNode{key, data, nullptr, nullptr};
return n; return n;
} }
if (key < node->key) if (key < node->key)
@@ -38,11 +38,11 @@ Node* TBST::insert(Node* node, const int key, TEmployee *data)
TEmployee *TBST::Search(int key) const TEmployee *TBST::Search(int key) const
{ {
const Node* result = search(root, key); const BSTNode* result = search(root, key);
return result ? result->data : nullptr; return result ? result->data : nullptr;
} }
Node* TBST::search(Node* node, const int key) BSTNode* TBST::search(BSTNode* node, const int key)
{ {
if (node == nullptr) if (node == nullptr)
return nullptr; return nullptr;
@@ -59,7 +59,7 @@ void TBST::Delete(const int key)
root = remove(root, key); root = remove(root, key);
} }
Node *TBST::remove(Node *node, const int key) BSTNode *TBST::remove(BSTNode *node, const int key)
{ {
if (node == nullptr) if (node == nullptr)
return nullptr; return nullptr;
@@ -76,21 +76,21 @@ Node *TBST::remove(Node *node, const int key)
} }
// Right child only // Right child only
if (node->left == nullptr) { if (node->left == nullptr) {
Node* child = node->right; BSTNode* child = node->right;
delete node->data; delete node->data;
delete node; delete node;
return child; return child;
} }
// Left child only // Left child only
if (node->right == nullptr) { if (node->right == nullptr) {
Node* child = node->left; BSTNode* child = node->left;
delete node->data; delete node->data;
delete node; delete node;
return child; return child;
} }
// Two children // Two children
else { else {
Node* minRight = findMin(node->right); BSTNode* minRight = findMin(node->right);
node->key = minRight->key; node->key = minRight->key;
node->data = minRight->data; node->data = minRight->data;
node->right = remove(minRight->right, minRight->key); node->right = remove(minRight->right, minRight->key);
@@ -99,7 +99,7 @@ Node *TBST::remove(Node *node, const int key)
return node; return node;
} }
Node* TBST::findMin(Node* node) BSTNode* TBST::findMin(BSTNode* node)
{ {
while (node && node->left) while (node && node->left)
node = node->left; node = node->left;
@@ -108,7 +108,7 @@ Node* TBST::findMin(Node* node)
/// Traversals /// Traversals
/// Private helpers /// Private helpers
void TBST::preorder(const Node* node) void TBST::preorder(const BSTNode* node)
{ {
if (!node) if (!node)
return; return;
@@ -117,7 +117,7 @@ void TBST::preorder(const Node* node)
preorder(node->right); preorder(node->right);
} }
void TBST::inorder(const Node* node) void TBST::inorder(const BSTNode* node)
{ {
if (!node) if (!node)
return; return;
@@ -126,7 +126,7 @@ void TBST::inorder(const Node* node)
inorder(node->right); inorder(node->right);
} }
void TBST::postorder(const Node *node) void TBST::postorder(const BSTNode *node)
{ {
if (!node) if (!node)
return; return;
@@ -135,23 +135,22 @@ void TBST::postorder(const Node *node)
std::cout << "[" << node->key << "] "; std::cout << "[" << node->key << "] ";
} }
void TBST::levelorder(const Node* node) void TBST::levelorder(const BSTNode* node)
{ {
if (!node) if (!node)
return; return;
TTreeQueue q; TTreeQueue<BSTNode> q;
q.Enqueue(const_cast<Node*>(node)); q.Enqueue(const_cast<BSTNode*>(node));
while (!q.IsEmpty()) { while (!q.IsEmpty()) {
const Node* cur = q.Dequeue(); const BSTNode* cur = q.Dequeue();
std::cout << "[" << cur->key << "] "; std::cout << "[" << cur->key << "] ";
if (cur->left) if (cur->left)
q.Enqueue(cur->left); q.Enqueue(cur->left);
if (cur->right) if (cur->right)
q.Enqueue(cur->right); q.Enqueue(cur->right);
} }
} }
void TBST::Inorder() const void TBST::Inorder() const
@@ -176,7 +175,4 @@ void TBST::LevelOrder() const
{ {
levelorder(root); levelorder(root);
std::cout << std::endl; std::cout << std::endl;
} }

View File

@@ -2,36 +2,26 @@
#define IKT203_COURSE_ASSIGNMENTS_TBST_H #define IKT203_COURSE_ASSIGNMENTS_TBST_H
#include "TEmployee.h" #include "TEmployee.h"
struct BSTNode {
struct Node {
int key; int key;
TEmployee* data; TEmployee* data;
Node* left; BSTNode* left;
Node* right; BSTNode* right;
}; };
class TBST { class TBST {
private: private:
Node* root; BSTNode* root;
static Node* insert(Node* node, int key, TEmployee* data); static BSTNode* insert(BSTNode* node, int key, TEmployee* data);
static BSTNode* search(BSTNode* node, int key);
static Node* search(Node* node, int key); static BSTNode* remove(BSTNode* node, int key);
static void inorder(const BSTNode* node);
static Node* remove(Node* node, int key); static void preorder(const BSTNode* node);
static void postorder(const BSTNode* node);
static void inorder(const Node* node); static void levelorder(const BSTNode* node);
static void destroy(BSTNode* node);
static void preorder(const Node* node); static BSTNode* findMin(BSTNode* node);
static void postorder(const Node* node);
static void levelorder(const Node* node);
static void destroy(Node* node);
static Node* findMin(Node* node);
public: public:
TBST() = default; TBST() = default;
@@ -40,13 +30,9 @@ class TBST {
void Insert(int key, TEmployee* data); void Insert(int key, TEmployee* data);
[[nodiscard]] TEmployee* Search(int key) const; [[nodiscard]] TEmployee* Search(int key) const;
void Delete(int key); void Delete(int key);
void Inorder() const; void Inorder() const;
void Preorder() const; void Preorder() const;
void Postorder() const; void Postorder() const;
void LevelOrder() const; void LevelOrder() const;
}; };
#endif //IKT203_COURSE_ASSIGNMENTS_TBST_H #endif //IKT203_COURSE_ASSIGNMENTS_TBST_H

View File

@@ -1,37 +0,0 @@
#include "TTreeQueue.h"
#include <stdexcept>
void TTreeQueue::Enqueue(Node* n)
{
if (n == nullptr)
return;
if (IsFull())
throw std::overflow_error("Queue Overflow");
queue[tail] = n;
tail = (tail + 1) % MAX_SIZE;
count++;
}
Node* TTreeQueue::Dequeue()
{
if (IsEmpty())
throw std::underflow_error("Empty Queue");
Node* n = queue[head];
if (n == nullptr)
return nullptr;
head = (head + 1) % MAX_SIZE;
count--;
return n;
}
bool TTreeQueue::IsEmpty() const
{
return count == 0;
}
bool TTreeQueue::IsFull() const
{
return count == MAX_SIZE;
}

View File

@@ -2,13 +2,15 @@
#define TQUEUE_H #define TQUEUE_H
#define MAX_SIZE 200 #define MAX_SIZE 200
#include <stdexcept>
#include "TBST.h" #include "TBST.h"
template <typename T>
struct TTreeQueue { struct TTreeQueue {
Node* queue[MAX_SIZE]; T* queue[MAX_SIZE];
int head = 0; int head = 0;
int tail = 0; int tail = 0;
int count = 0; int count = 0;
@@ -17,10 +19,38 @@ struct TTreeQueue {
TTreeQueue() = default; TTreeQueue() = default;
~TTreeQueue() = default; ~TTreeQueue() = default;
void Enqueue(Node* n); void Enqueue(T* n)
Node* Dequeue(); {
[[nodiscard]] bool IsEmpty() const; if (n == nullptr)
[[nodiscard]] bool IsFull() const; return;
if (IsFull())
throw std::overflow_error("Queue Overflow");
queue[tail] = n;
tail = (tail + 1) % MAX_SIZE;
count++;
}
T* Dequeue()
{
if (IsEmpty())
throw std::underflow_error("Empty Queue");
T* n = queue[head];
if (n == nullptr)
return nullptr;
head = (head + 1) % MAX_SIZE;
count--;
return n;
}
bool IsEmpty() const
{
return count == 0;
}
bool IsFull() const
{
return count == MAX_SIZE;
}
}; };

View File

@@ -3,6 +3,7 @@
#include <limits> #include <limits>
int RunApp() { int RunApp() {
//Reading names from file for BST population
bst = new TBST(); bst = new TBST();
/* Path to the names data file /* Path to the names data file
This is MY absolute path -- change to your local path for this to read properly This is MY absolute path -- change to your local path for this to read properly
@@ -11,6 +12,8 @@ int RunApp() {
const std::string filename = "C:\\Users\\csand\\IKT203\\Exam\\IKT203Exam\\DATA\\random_names.txt"; const std::string filename = "C:\\Users\\csand\\IKT203\\Exam\\IKT203Exam\\DATA\\random_names.txt";
readNamesFromFile(filename, onNameRead); readNamesFromFile(filename, onNameRead);
// BST traversal -- comment out the entire block
// when done inspecting for more manageable terminal output
pack("Inorder traversal (sorted by ID)"); pack("Inorder traversal (sorted by ID)");
bst->Inorder(); bst->Inorder();
@@ -44,8 +47,36 @@ int RunApp() {
else else
std::cout << "ID not found\n" << std::endl; std::cout << "ID not found\n" << std::endl;
bst->Inorder(); bst->Inorder();
// End of BST block
// Start of AVL block
// Again, comment out the block if terminal output is
// too noisy
pack("AVL");
avl = new TAVL;
TAVL::Populate(avl, 100, 1, 200);
pack("Inorder");
avl->PrintOrder(TAVL::Inorder);
pack("Postorder");
avl->PrintOrder(TAVL::Postorder);
pack("Preorder");
avl->PrintOrder(TAVL::Preorder);
pack("Levelorder");
avl->PrintOrder(TAVL::LevelOrder);
// End of AVL block
// Cleaning to free up memory.
// Used only at end of runtime, but useful for when runtime needs
// to be continuous
pack ("Cleaning up"); pack ("Cleaning up");
delete bst; delete bst;
delete avl;
return 0; return 0;
} }

View File

@@ -8,6 +8,7 @@
#include <TTreeQueue.h> #include <TTreeQueue.h>
#include <unordered_set> #include <unordered_set>
#include "TAVL.h"
#include "TBST.h" #include "TBST.h"
#include "TEmployee.h" #include "TEmployee.h"
#include "Utils.h" #include "Utils.h"
@@ -17,6 +18,7 @@
/// all unique IDs /// all unique IDs
inline std::unordered_set<int> usedIds; inline std::unordered_set<int> usedIds;
static TBST* bst; static TBST* bst;
static TAVL* avl;
int RunApp(); int RunApp();
@@ -56,4 +58,6 @@ inline void pack(const std::string& line)
printline(); printline();
} }
#endif // OPTION1_H #endif // OPTION1_H

View File

@@ -3,6 +3,7 @@
#define SHARED_LIB_H #define SHARED_LIB_H
#include <string> #include <string>
#include <functional> #include <functional>
#include "../Assignment-03/TAVL.h"
/// <summary> /// <summary>
/// Delegate type for processing a name read from a file. /// Delegate type for processing a name read from a file.
@@ -97,4 +98,4 @@ typedef bool (*FSongRead)(
void ReadSongsFromFile(const std::string& aFilename, FSongRead aOnSongRead); void ReadSongsFromFile(const std::string& aFilename, FSongRead aOnSongRead);
#endif // SHARED_LIB_H #endif // SHARED_LIB_H