diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/CMakeLists.txt b/Exam/IKT203Exam/Portfolio/Assignment-03/CMakeLists.txt index 7166168..0bb3ab2 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/CMakeLists.txt +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/CMakeLists.txt @@ -10,7 +10,8 @@ add_executable(Assignment-03 TBST.cpp TBST.h TEmployee.h - TTreeQueue.cpp + TAVL.cpp + TAVL.h ) # Conditionally add the correct source file diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.cpp b/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.cpp new file mode 100644 index 0000000..a464581 --- /dev/null +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.cpp @@ -0,0 +1,222 @@ +#include "TAVL.h" + +#include +#include +#include +#include + +#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 q; + q.Enqueue(const_cast(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); +} + +/// Populates AVL tree The AVL tree to be populated +///How many elements to be populated into the tree +///Lower bounds of key value range (e.g., the lower limit of element value) +///Upper bounds of key value range (e.g., higher limit og element value) +/// None +void TAVL::Populate(TAVL* avl, const int count, const int minRange, const int maxRange) +{ + std::unordered_set 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); + } +} + + + + + + + + + + diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.h b/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.h new file mode 100644 index 0000000..96e6c30 --- /dev/null +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.h @@ -0,0 +1,49 @@ +#ifndef IKT203_COURSE_ASSIGNMENTS_TAVL_H +#define IKT203_COURSE_ASSIGNMENTS_TAVL_H +#include + + +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 \ No newline at end of file diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.cpp b/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.cpp index 93341b2..59381d9 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.cpp +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.cpp @@ -5,7 +5,7 @@ #include "TTreeQueue.h" -void TBST::destroy(Node *node) +void TBST::destroy(BSTNode *node) { if (!node) return; @@ -20,10 +20,10 @@ void TBST::Insert(const int key, TEmployee *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) { - auto* n = new Node{key, data, nullptr, nullptr}; + auto* n = new BSTNode{key, data, nullptr, nullptr}; return n; } if (key < node->key) @@ -38,11 +38,11 @@ Node* TBST::insert(Node* node, const int key, TEmployee *data) TEmployee *TBST::Search(int key) const { - const Node* result = search(root, key); + const BSTNode* result = search(root, key); return result ? result->data : nullptr; } -Node* TBST::search(Node* node, const int key) +BSTNode* TBST::search(BSTNode* node, const int key) { if (node == nullptr) return nullptr; @@ -59,7 +59,7 @@ void TBST::Delete(const int key) root = remove(root, key); } -Node *TBST::remove(Node *node, const int key) +BSTNode *TBST::remove(BSTNode *node, const int key) { if (node == nullptr) return nullptr; @@ -76,21 +76,21 @@ Node *TBST::remove(Node *node, const int key) } // Right child only if (node->left == nullptr) { - Node* child = node->right; + BSTNode* child = node->right; delete node->data; delete node; return child; } // Left child only if (node->right == nullptr) { - Node* child = node->left; + BSTNode* child = node->left; delete node->data; delete node; return child; } // Two children else { - Node* minRight = findMin(node->right); + BSTNode* minRight = findMin(node->right); node->key = minRight->key; node->data = minRight->data; node->right = remove(minRight->right, minRight->key); @@ -99,7 +99,7 @@ Node *TBST::remove(Node *node, const int key) return node; } -Node* TBST::findMin(Node* node) +BSTNode* TBST::findMin(BSTNode* node) { while (node && node->left) node = node->left; @@ -108,7 +108,7 @@ Node* TBST::findMin(Node* node) /// Traversals /// Private helpers -void TBST::preorder(const Node* node) +void TBST::preorder(const BSTNode* node) { if (!node) return; @@ -117,7 +117,7 @@ void TBST::preorder(const Node* node) preorder(node->right); } -void TBST::inorder(const Node* node) +void TBST::inorder(const BSTNode* node) { if (!node) return; @@ -126,7 +126,7 @@ void TBST::inorder(const Node* node) inorder(node->right); } -void TBST::postorder(const Node *node) +void TBST::postorder(const BSTNode *node) { if (!node) return; @@ -135,23 +135,22 @@ void TBST::postorder(const Node *node) std::cout << "[" << node->key << "] "; } -void TBST::levelorder(const Node* node) +void TBST::levelorder(const BSTNode* node) { if (!node) return; - TTreeQueue q; - q.Enqueue(const_cast(node)); + TTreeQueue q; + q.Enqueue(const_cast(node)); while (!q.IsEmpty()) { - const Node* cur = q.Dequeue(); + const BSTNode* cur = q.Dequeue(); std::cout << "[" << cur->key << "] "; if (cur->left) q.Enqueue(cur->left); if (cur->right) q.Enqueue(cur->right); } - } void TBST::Inorder() const @@ -176,7 +175,4 @@ void TBST::LevelOrder() const { levelorder(root); std::cout << std::endl; -} - - - +} \ No newline at end of file diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.h b/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.h index c834eab..7a26589 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.h +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.h @@ -2,36 +2,26 @@ #define IKT203_COURSE_ASSIGNMENTS_TBST_H #include "TEmployee.h" - -struct Node { +struct BSTNode { int key; TEmployee* data; - Node* left; - Node* right; + BSTNode* left; + BSTNode* right; }; - class TBST { private: - Node* root; + BSTNode* root; - static Node* insert(Node* node, int key, TEmployee* data); - - static Node* search(Node* node, int key); - - static Node* remove(Node* node, int key); - - static void inorder(const Node* node); - - static void preorder(const Node* node); - - static void postorder(const Node* node); - - static void levelorder(const Node* node); - - static void destroy(Node* node); - - static Node* findMin(Node* node); + static BSTNode* insert(BSTNode* node, int key, TEmployee* data); + static BSTNode* search(BSTNode* node, int key); + static BSTNode* remove(BSTNode* node, int key); + static void inorder(const BSTNode* node); + static void preorder(const BSTNode* node); + static void postorder(const BSTNode* node); + static void levelorder(const BSTNode* node); + static void destroy(BSTNode* node); + static BSTNode* findMin(BSTNode* node); public: TBST() = default; @@ -40,13 +30,9 @@ class TBST { void Insert(int key, TEmployee* data); [[nodiscard]] TEmployee* Search(int key) const; void Delete(int key); - void Inorder() const; void Preorder() const; void Postorder() const; - void LevelOrder() const; }; - - #endif //IKT203_COURSE_ASSIGNMENTS_TBST_H \ No newline at end of file diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TTreeQueue.cpp b/Exam/IKT203Exam/Portfolio/Assignment-03/TTreeQueue.cpp deleted file mode 100644 index 380eb55..0000000 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/TTreeQueue.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "TTreeQueue.h" - -#include - - -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; -} diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TTreeQueue.h b/Exam/IKT203Exam/Portfolio/Assignment-03/TTreeQueue.h index cd2c599..ba28e31 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/TTreeQueue.h +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/TTreeQueue.h @@ -2,13 +2,15 @@ #define TQUEUE_H #define MAX_SIZE 200 +#include + #include "TBST.h" - +template struct TTreeQueue { - Node* queue[MAX_SIZE]; + T* queue[MAX_SIZE]; int head = 0; int tail = 0; int count = 0; @@ -17,10 +19,38 @@ struct TTreeQueue { TTreeQueue() = default; ~TTreeQueue() = default; - void Enqueue(Node* n); - Node* Dequeue(); - [[nodiscard]] bool IsEmpty() const; - [[nodiscard]] bool IsFull() const; + void Enqueue(T* n) + { + if (n == nullptr) + 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; + } }; diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/option1.cpp b/Exam/IKT203Exam/Portfolio/Assignment-03/option1.cpp index ba11baf..a08ff69 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/option1.cpp +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/option1.cpp @@ -3,6 +3,7 @@ #include int RunApp() { + //Reading names from file for BST population bst = new TBST(); /* Path to the names data file 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"; readNamesFromFile(filename, onNameRead); + // BST traversal -- comment out the entire block + // when done inspecting for more manageable terminal output pack("Inorder traversal (sorted by ID)"); bst->Inorder(); @@ -44,8 +47,36 @@ int RunApp() { else std::cout << "ID not found\n" << std::endl; 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"); delete bst; + delete avl; return 0; } diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/option1.h b/Exam/IKT203Exam/Portfolio/Assignment-03/option1.h index a19f70e..f3096e1 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/option1.h +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/option1.h @@ -8,6 +8,7 @@ #include #include +#include "TAVL.h" #include "TBST.h" #include "TEmployee.h" #include "Utils.h" @@ -17,6 +18,7 @@ /// all unique IDs inline std::unordered_set usedIds; static TBST* bst; +static TAVL* avl; int RunApp(); @@ -56,4 +58,6 @@ inline void pack(const std::string& line) printline(); } + + #endif // OPTION1_H diff --git a/Exam/IKT203Exam/Portfolio/SharedLib/SharedLib.h b/Exam/IKT203Exam/Portfolio/SharedLib/SharedLib.h index 553ad6c..0406827 100644 --- a/Exam/IKT203Exam/Portfolio/SharedLib/SharedLib.h +++ b/Exam/IKT203Exam/Portfolio/SharedLib/SharedLib.h @@ -3,6 +3,7 @@ #define SHARED_LIB_H #include #include +#include "../Assignment-03/TAVL.h" /// /// 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); -#endif // SHARED_LIB_H \ No newline at end of file +#endif // SHARED_LIB_H