diff --git a/Exam/IKT203Exam/Portfolio/Assignment-02/option1.cpp b/Exam/IKT203Exam/Portfolio/Assignment-02/option1.cpp index bb87580..5af631d 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-02/option1.cpp +++ b/Exam/IKT203Exam/Portfolio/Assignment-02/option1.cpp @@ -1,43 +1,38 @@ -// Option 1 (Standard): Console Text Editor. -// - #include #include #include "option1.h" - #include - #include "SharedLib.h" #include "TLinkedList.h" #include "TPerson.h" -// Assignment specific helpers in option1.h - - +// Entry point for Category 2, Option 1 (Cruise Ship Manifest). +// Steps: +// 1) Load names from DATA/random_names.txt into employee and guest lists +// 2) Merge-sort both lists alphabetically (lastName, firstName) +// 3) Convert guests to an array and quick-sort by cabinSize, then lastName +// 4) Allow the user to search (binary search) by surname in the chosen list int RunApp() { - /* Path to the names data file - This is MY absolute path -- change to your local path for this to read properly - something like "C:\Users\Username\FolderYouSavedTheSubmissionIn\Exam\IKT203Exam\DATA\random_names.txt" - Double slash is needed for string to pass the correct file path */ - const std::string filename = "C:\\Users\\csand\\IKT203\\Exam\\IKT203Exam\\DATA\\random_names.txt"; + // Path to the names data file. + // IMPORTANT: working directory must be set so that "DATA/random_names.txt" resolves correctly. + const std::string filename = "DATA/random_names.txt"; pack("Reading names and grouping them."); // Call the utility function with the name callback readNamesFromFile(filename, onNameRead); - pack("Finished reading names."); - - - /////////////////////////// Merge sorting /////////////////////////// + // Sort both employee and guest linked lists alphabetically + // using the linked-list merge sort implementation in TLinkedList. e.Sort(); g.Sort(); pack("Sorting."); // Attempt at "beautifying" the terminal output somewhat pack("Employees merge sorted alphabetically."); - TPerson* employeeAlphaSort[e.GetSize()]; + const int employeeSize = e.GetSize(); + auto** employeeAlphaSort = new TPerson*[employeeSize]; printline(); for (int i = 0; i < e.GetSize(); i++) { std::cout << "[" << i << "] " << e.GetAtIndex(i).lastName << ", " << e.GetAtIndex(i).firstName @@ -45,8 +40,9 @@ int RunApp() employeeAlphaSort[i] = new TPerson(e.GetAtIndex(i)); } printline(); - pack("Guests merger sorted alphabetically."); - TPerson* guestAlphaSort[g.GetSize()]; + pack("Guests merge sorted alphabetically."); + const int guestSize = g.GetSize(); + auto** guestAlphaSort = new TPerson*[guestSize]; printline(); for (int i = 0; i < g.GetSize(); i++) { std::cout << "[" << i << "] " << g.GetAtIndex(i).lastName << ", " << g.GetAtIndex(i).firstName @@ -55,15 +51,15 @@ int RunApp() } printline(); - - /////////////////////////// Quick sorting /////////////////////////// + // Build an array of guests and quick-sort it by: + // 1) cabinSize (ascending), then 2) lastName. + // This array is used to optimise cabin assignment. // creating array from guest linked list auto** guestList = new TPerson*[guestCount]; for (int i = 0; i < guestCount; i++) { guestList[i] = new TPerson(g.GetAtIndex(i)); } - // Quicksorting the guestlist array Utils::QuickSort(guestList, 0, guestCount - 1); pack("Guests quick sorted by 1) cabinsize, 2) lastname."); @@ -74,19 +70,16 @@ int RunApp() } printline(); - - - - - - /////////////////////////// Binary search /////////////////////////// + // Let the user choose whether to search employees or guests, + // then perform binary search on the corresponding alphabetically + // sorted array and print all matches with that surname. int choice; std::string target; std::cout << "What list do you want to search through: \n [1] Employee\n [2] Guest" << std::endl; std::cin >> choice; std::cin.ignore(std::numeric_limits::max(), '\n'); - std::cout << "Enter surname to search: " << std::endl; + std::cout << "Enter name to search for: " << std::endl; std::getline(std::cin, target); switch (choice) { @@ -100,21 +93,31 @@ switch (choice) { } } - - - - - - /////////////////////////// Cleanup before exit /////////////////////////// - for (int i = 0; i < guestCount; i++) { + // Delete all dynamically allocated TPerson objects from: + // - alphabetical employee array + // - alphabetical guest array + // - quick-sorted guestList array + // Then clear the linked lists to avoid memory leaks. + + for (int i = 0; i < employeeSize; ++i) + delete employeeAlphaSort[i]; + delete[] employeeAlphaSort; + + for (int i = 0; i < guestSize; ++i) + delete guestAlphaSort[i]; + delete[] guestAlphaSort; + + for (int i = 0; i < guestCount; ++i) delete guestList[i]; - } delete[] guestList; + while (e.GetSize() > 0) e.Remove(0); while (g.GetSize() > 0) g.Remove(0); + pack("Cleaned up memory"); - return 0; + return 0; + } \ No newline at end of file diff --git a/Exam/IKT203Exam/Portfolio/Assignment-02/option1.h b/Exam/IKT203Exam/Portfolio/Assignment-02/option1.h index 17d88f8..6bebdb4 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-02/option1.h +++ b/Exam/IKT203Exam/Portfolio/Assignment-02/option1.h @@ -1,4 +1,6 @@ -// option1.h : Option 1 (Standard): Console Text Editor. +// Option 1 (Standard): Cruise Ship Manifest. +// Uses linked lists, merge sort, quick sort, and binary search +// to manage guest and employee manifests from random_names.txt. #pragma once @@ -7,8 +9,13 @@ #include "TLinkedList.h" #include "TPerson.h" +// Global lists and counters used across the assignment: +// - 'e' stores EMPLOYEE records +// - 'g' stores GUEST records +// - guestCount / employCount track how many were loaded inline TLinkedList g, e; -inline int guestCount, employCount = 0; +inline int guestCount = 0; +inline int employCount = 0; @@ -42,9 +49,13 @@ static bool NameReadCallback(const int aIndex, const int aTotalCount, const std: } */ -// *Inspired* by the provided NameReadCallback given above +// Callback used by readNamesFromFile. +// - Creates a TPerson with status (EMPLOYEE or GUEST) +// - First 1500 entries are EMPLOYEE, the rest are GUEST +// - Appends each person to the appropriate linked list and updates counters static bool onNameRead(const int aIndex, const int aTotalCount, const std::string& aFirstName, const std::string& aLastName) { + // Determine status based on index: first 1500 are employees, rest are guests. const ENumStatus status = (aIndex < 1500) ? EMPLOYEE : GUEST; const TPerson p(aFirstName, aLastName, status); @@ -64,7 +75,10 @@ static bool onNameRead(const int aIndex, const int aTotalCount, const std::strin return true; } - +// Binary-search helper: +// - Performs binary search on a sorted array of TPerson* (alphabetical by last name) +// - 'target' is the surname entered by the user +// - Expands left/right from the first match to find and print all matches inline void SearchAndPrint(TPerson** targetArray, int arraySize, const std::string& target) { int index = Utils::BinarySearch(targetArray, 0, arraySize - 1, target); @@ -77,10 +91,12 @@ inline void SearchAndPrint(TPerson** targetArray, int arraySize, const std::stri int left = index - 1; int right = index + 1; + // Move left while neighbouring entries share the same first or last name while (left >= 0 && (targetArray[left]->firstName == target || targetArray[left]->lastName == target)) { --left; } + // Move right while neighbouring entries share the same first or last name while (right < arraySize && (targetArray[right]->firstName == target || targetArray[right]->lastName == target)) { ++right; } diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.cpp b/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.cpp index a464581..c6c2ca5 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.cpp +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.cpp @@ -1,10 +1,6 @@ #include "TAVL.h" - -#include #include #include -#include - #include "TTreeQueue.h" #include "Utils.h" @@ -57,7 +53,10 @@ AVLNode *TAVL::rotateLeft(AVLNode *x) return y; } -// Comment out std::cout lines for no rotation output lines +// Recursive AVL insert: +// - Insert key as in a normal BST. +// - Update node height. +// - Compute balance factor and apply the appropriate rotation if unbalanced. AVLNode *TAVL::insert(AVLNode *n, const int key) { if (!n) @@ -74,23 +73,25 @@ AVLNode *TAVL::insert(AVLNode *n, const int key) if (balance > 1 && key < n->left->key) { - std::cout << "L-L rotation on [" << n->key << "]" << std::endl; + //std::cout << "L-L rotation on [" << n->key << "]" << std::endl; <--- uncomment for terminal output of rotations return rotateRight(n); } if (balance < -1 && key > n->right->key) { - std::cout << "R-R rotation on [" << n->key << "]" << std::endl; + //std::cout << "R-R rotation on [" << n->key << "]" << std::endl; <--- uncomment for terminal output of rotations return rotateLeft(n); } if (balance > 1 && key > n->left->key) - { std::cout << "L-R rotation on [" << n->key << "]" << std::endl; + { + //std::cout << "L-R rotation on [" << n->key << "]" << std::endl; <--- uncomment for terminal output of rotations 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; + { + //std::cout << "R-L rotation on [" << n->key << "]" << std::endl; <--- uncomment for terminal output of rotations n->right = rotateRight(n->right); return rotateLeft(n); } @@ -144,11 +145,17 @@ void TAVL::levelorder(const AVLNode* node) } // Public functions +/// Insert node Node key value (int) +/// None void TAVL::Insert(const int key) { root = insert(root, key); } +/// Inorder callback AVLNode *node +/// Bool bool TAVL::Inorder(const AVLNode *node) { if (!node) @@ -158,6 +165,9 @@ bool TAVL::Inorder(const AVLNode *node) return true; } +/// Postorder callback AVLNode *node +/// Bool bool TAVL::Postorder(const AVLNode *node) { if (!node) @@ -167,6 +177,9 @@ bool TAVL::Postorder(const AVLNode *node) return true; } +/// Preorder callback AVLNode *node +/// Bool bool TAVL::Preorder(const AVLNode *node) { if (!node) @@ -176,6 +189,9 @@ bool TAVL::Preorder(const AVLNode *node) return true; } +/// LevelOrder callback AVLNode *node +/// Bool bool TAVL::LevelOrder(const AVLNode *node) { if (!node) @@ -185,6 +201,9 @@ bool TAVL::LevelOrder(const AVLNode *node) return true; } +/// Prints the desired sorting order Callback for the desired ordering algorithm (e.g. PrintOrder(LevelOrder) will print the Level Order algorithm to the terminal) +/// None void TAVL::PrintOrder(FOrderTraversal cb) { if (!cb) @@ -192,6 +211,8 @@ void TAVL::PrintOrder(FOrderTraversal cb) cb(root); } +// Helper to build an AVL tree with 'count' unique random keys +// in the range [minRange, maxRange]. Used only for demonstration in RunApp() /// Populates AVL tree The AVL tree to be populated ///How many elements to be populated into the tree @@ -205,7 +226,7 @@ void TAVL::Populate(TAVL* avl, const int count, const int minRange, const int ma int val = Utils::RandomInt(minRange, maxRange); while (AVLset.count(val)) val = Utils::RandomInt(minRange, maxRange); - std::cout << "Inserting [" << val << "]" << std::endl; + //std::cout << "Inserting [" << val << "]" << std::endl; <----- Uncomment for terminal output of insertions avl->Insert(val); AVLset.insert(val); } diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.h b/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.h index 96e6c30..7f8270c 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.h +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/TAVL.h @@ -1,8 +1,8 @@ #ifndef IKT203_COURSE_ASSIGNMENTS_TAVL_H #define IKT203_COURSE_ASSIGNMENTS_TAVL_H -#include - +// Node used in the AVL tree. +// Stores only an integer key and height (no TEmployee data). struct AVLNode { int key; AVLNode* left; @@ -14,6 +14,8 @@ struct AVLNode { typedef bool (*FOrderTraversal)(const AVLNode* AVLNode); +// Self-balancing AVL tree used to demonstrate rotations and traversals. +// Only stores integer keys; no payload data is required for this assignment. class TAVL { private: AVLNode* root; diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.cpp b/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.cpp index 59381d9..c8a16cd 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.cpp +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.cpp @@ -1,7 +1,5 @@ #include "TBST.h" - #include - #include "TTreeQueue.h" @@ -11,10 +9,15 @@ void TBST::destroy(BSTNode *node) return; destroy(node->left); destroy(node->right); + // TBST owns the TEmployee* stored in each node, so delete it here. delete node->data; delete node; } +/// Insert node Node key value (int) +/// Employee data (TEmployee) +/// None void TBST::Insert(const int key, TEmployee *data) { root = insert(root, key, data); @@ -30,12 +33,19 @@ BSTNode* TBST::insert(BSTNode* node, const int key, TEmployee *data) node->left = insert(node->left, key, data); else if (key > node->key) node->right = insert(node->right, key, data); - else - std::cout << "Error with node insertion" << std::endl; - + else { + // Duplicate key: do not modify the existing node. + // 'data' was allocated by the caller, so we must delete it here + // to avoid a memory leak. + std::cout << "Duplicate key [" << key << "], ignoring insert." << std::endl; + delete data; + } return node; } +/// Search for node Node key value (int) +/// TEmployee TEmployee *TBST::Search(int key) const { const BSTNode* result = search(root, key); @@ -54,6 +64,9 @@ BSTNode* TBST::search(BSTNode* node, const int key) return search(node->right, key); } +/// Delete node Node key value (int) +/// None void TBST::Delete(const int key) { root = remove(root, key); @@ -88,7 +101,10 @@ BSTNode *TBST::remove(BSTNode *node, const int key) delete node; return child; } - // Two children + // Two children: + // 1) Find the smallest node in the right subtree (inorder successor) + // 2) Copy its key + data into the current node + // 3) Remove the successor node from the right subtree else { BSTNode* minRight = findMin(node->right); node->key = minRight->key; @@ -106,8 +122,8 @@ BSTNode* TBST::findMin(BSTNode* node) return node; } -/// Traversals -/// Private helpers +// Traversals +// Private helpers void TBST::preorder(const BSTNode* node) { if (!node) @@ -153,24 +169,32 @@ void TBST::levelorder(const BSTNode* node) } } +/// Inorder sorting None void TBST::Inorder() const { inorder(root); std::cout << std::endl; } +/// Preorder sorting None void TBST::Preorder() const { preorder(root); std::cout << std::endl; } +/// Postorder sorting None void TBST::Postorder() const { postorder(root); std::cout << std::endl; } +/// LevelOrder sorting None void TBST::LevelOrder() const { levelorder(root); diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.h b/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.h index 7a26589..d9d90ea 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.h +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/TBST.h @@ -2,13 +2,19 @@ #define IKT203_COURSE_ASSIGNMENTS_TBST_H #include "TEmployee.h" +// Node in the Binary Search Tree. +// Owns a single TEmployee* which is deleted by TBST::destroy/remove. struct BSTNode { - int key; - TEmployee* data; + int key; // employee ID + TEmployee* data; // employee record BSTNode* left; BSTNode* right; }; +// Standard Binary Search Tree for TEmployee* keyed by employee ID. +// Responsibilities: +// - Owns all TEmployee objects it contains. +// - Provides insert, search, delete, and four traversal methods. class TBST { private: BSTNode* root; diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TEmployee.h b/Exam/IKT203Exam/Portfolio/Assignment-03/TEmployee.h index dcd49fd..e9953c3 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/TEmployee.h +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/TEmployee.h @@ -3,7 +3,8 @@ #include #include - +// Simple employee record used in Category 3. +// 'id' is set later by IdGenerator and used as the BST key. struct TEmployee { std::string firstName; std::string lastName; diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/TTreeQueue.h b/Exam/IKT203Exam/Portfolio/Assignment-03/TTreeQueue.h index ba28e31..847d3f2 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/TTreeQueue.h +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/TTreeQueue.h @@ -3,10 +3,10 @@ #define MAX_SIZE 200 #include - #include "TBST.h" - +// Fixed-size circular queue used by the BST and AVL level-order traversals. +// Stores raw pointers to tree nodes (T*). Does not own the nodes. template struct TTreeQueue { @@ -22,7 +22,7 @@ struct TTreeQueue { void Enqueue(T* n) { if (n == nullptr) - return; + return; // ignore null pointers, nothing to enqueue if (IsFull()) throw std::overflow_error("Queue Overflow"); queue[tail] = n; diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/option1.cpp b/Exam/IKT203Exam/Portfolio/Assignment-03/option1.cpp index a08ff69..c3ad44d 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/option1.cpp +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/option1.cpp @@ -1,19 +1,25 @@ #include "option1.h" - #include +// Entry point for Category 3, Option 1. +// Demonstrates: +// 1) Building a BST of 200 employees from DATA/random_names.txt +// 2) Running all BST traversals +// 3) Searching and deleting by employee ID +// 4) Building and printing an AVL tree with random integer keys 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 - something like "C:\Users\Username\FolderYouSavedTheSubmissionIn\Exam\IKT203Exam\DATA\random_names.txt" - Double slash is needed for string to pass the correct file path */ - const std::string filename = "C:\\Users\\csand\\IKT203\\Exam\\IKT203Exam\\DATA\\random_names.txt"; + + // Read 200 employees from the names file and populate the BST. + // IMPORTANT: Working directory must be the Portfolio/Assignment-03 folder + // so that "DATA/random_names.txt" resolves correctly. + const std::string filename = "DATA/random_names.txt"; readNamesFromFile(filename, onNameRead); - // BST traversal -- comment out the entire block - // when done inspecting for more manageable terminal output + // --- BST traversals --- + // These calls demonstrate all four traversal orders on the employee BST. + // Comment out this block if the console output becomes too noisy. pack("Inorder traversal (sorted by ID)"); bst->Inorder(); @@ -26,6 +32,8 @@ int RunApp() { pack("Postorder traversal"); bst->Postorder(); + // --- BST search demo --- + // Ask the user for an ID, search in the BST, and print the matching employee (if any). pack("Search function"); std::cout << "\nInput the ID you want to search for\n" << std::endl; int choice; @@ -36,6 +44,9 @@ int RunApp() { else std::cout << "ID not found" << std::endl; + // --- BST delete demo --- + // Ask the user for an ID, delete it from the BST if it exists, + // then print the new inorder traversal to show the updated structure. pack("Remove function"); std::cout << "\nInput the ID you want to remove\n" << std::endl; std::cin >> choice; @@ -49,13 +60,13 @@ int RunApp() { bst->Inorder(); // End of BST block - // Start of AVL block - // Again, comment out the block if terminal output is - // too noisy + // --- AVL demo --- + // Build an AVL tree using random integers in [1, 200]. + // This tree only stores keys (no TEmployee data) and is used + // to demonstrate balancing and traversals. pack("AVL"); avl = new TAVL; - TAVL::Populate(avl, 100, 1, 200); pack("Inorder"); avl->PrintOrder(TAVL::Inorder); @@ -71,9 +82,9 @@ int RunApp() { // End of AVL block - // Cleaning to free up memory. - // Used only at end of runtime, but useful for when runtime needs - // to be continuous + // --- Cleanup --- + // TBST destructor deletes all TEmployee objects it owns. + // Here we delete the tree objects themselves to avoid leaks. pack ("Cleaning up"); delete bst; delete avl; diff --git a/Exam/IKT203Exam/Portfolio/Assignment-03/option1.h b/Exam/IKT203Exam/Portfolio/Assignment-03/option1.h index f3096e1..8318cfc 100644 --- a/Exam/IKT203Exam/Portfolio/Assignment-03/option1.h +++ b/Exam/IKT203Exam/Portfolio/Assignment-03/option1.h @@ -3,25 +3,24 @@ #ifndef OPTION1_H #define OPTION1_H - #include -#include #include - #include "TAVL.h" #include "TBST.h" #include "TEmployee.h" #include "Utils.h" -#include "../../Submissions/Submission-04/BankAccount.h" -/// To keep track of used ID values to ensure -/// all unique IDs +// Global state for Category 3, Option 1: +// - bst: owns all TEmployee objects (deleted in TBST destructor) +// - avl: separate AVL tree used only to demonstrate balancing on int keys inline std::unordered_set usedIds; static TBST* bst; static TAVL* avl; int RunApp(); +// Assign a unique random employee ID in the range [1, 1000]. +// Uses 'usedIds' to avoid duplicates so the BST always has unique keys. inline void IdGenerator(TEmployee* employee) { int id = Utils::RandomInt(1, 1000); @@ -32,6 +31,11 @@ inline void IdGenerator(TEmployee* employee) usedIds.insert(id); employee->id = id; } + +// Callback used by readNamesFromFile. +// - Creates a new TEmployee from the given name. +// - Stops after 200 employees (as required by the assignment). +// - Generates a unique ID and inserts the employee into the BST. static bool onNameRead(const int index, const int aTotalCount, const std::string& aFirstName, const std::string& aLastName) { const auto e = new TEmployee(aFirstName, aLastName); @@ -50,6 +54,7 @@ inline void printline() std::cout << "----------------------------------------" << std::endl; } +// Helper to visually separate different demos (traversals, search, etc.) in the console output. inline void pack(const std::string& line) { std::cout << "\n\n\n" << std::endl; diff --git a/Exam/IKT203Exam/Portfolio/SharedLib/TLinkedList.cpp b/Exam/IKT203Exam/Portfolio/SharedLib/TLinkedList.cpp index 050129b..26b3f4c 100644 --- a/Exam/IKT203Exam/Portfolio/SharedLib/TLinkedList.cpp +++ b/Exam/IKT203Exam/Portfolio/SharedLib/TLinkedList.cpp @@ -149,8 +149,8 @@ TLinkedList::Node *TLinkedList::MergeList(Node *a, Node *b) return result; } -/// Time complexity O(n log n) at all times -/// Does NOT sort in place, so more memory is needed to complete +// Time complexity O(n log n) at all times +// Does NOT sort in place, so more memory is needed to complete TLinkedList::Node *TLinkedList::MergeSort(Node *head) { if (head == nullptr || head->next == nullptr) @@ -166,6 +166,8 @@ TLinkedList::Node *TLinkedList::MergeSort(Node *head) return MergeList(front, back); } +// Stable merge sort on the linked list. +// Time complexity: O(n log n), requires extra pointers but no extra arrays. void TLinkedList::Sort() { this->head = MergeSort(head); diff --git a/Exam/IKT203Exam/Portfolio/SharedLib/TLinkedList.h b/Exam/IKT203Exam/Portfolio/SharedLib/TLinkedList.h index a8956b4..8ba202b 100644 --- a/Exam/IKT203Exam/Portfolio/SharedLib/TLinkedList.h +++ b/Exam/IKT203Exam/Portfolio/SharedLib/TLinkedList.h @@ -3,12 +3,15 @@ #include "TPerson.h" +// Singly linked list of TPerson, used for the guest and employee manifests. +// Owns all its Node objects and frees them in the destructor. +// Supports append, prepend, insert, remove, indexed access, and merge-sort. class TLinkedList { private: struct Node { - TPerson person; + TPerson person; // stored by value Node* next; explicit Node(const TPerson& p) : person(p), next(nullptr) {} diff --git a/Exam/IKT203Exam/Portfolio/SharedLib/TPerson.h b/Exam/IKT203Exam/Portfolio/SharedLib/TPerson.h index 9753fb7..05861f7 100644 --- a/Exam/IKT203Exam/Portfolio/SharedLib/TPerson.h +++ b/Exam/IKT203Exam/Portfolio/SharedLib/TPerson.h @@ -9,7 +9,9 @@ enum ENumStatus { EMPLOYEE }; - +// Represents one person on the cruise ship. +// - 'status' tells us if they're a GUEST or EMPLOYEE +// - 'cabinSize' is random in [1, 4] and used for cabin grouping struct TPerson { std::string firstName; std::string lastName; @@ -20,6 +22,8 @@ struct TPerson { TPerson(std::string , std::string , ENumStatus); ~TPerson() = default; + // Comparison for alphabetical sorting: + // primary key: lastName, secondary key: firstName. bool operator<(const TPerson& other) const { if (lastName < other.lastName) return true; diff --git a/Exam/IKT203Exam/Portfolio/SharedLib/Utils.cpp b/Exam/IKT203Exam/Portfolio/SharedLib/Utils.cpp index 4b34f75..16cdadc 100644 --- a/Exam/IKT203Exam/Portfolio/SharedLib/Utils.cpp +++ b/Exam/IKT203Exam/Portfolio/SharedLib/Utils.cpp @@ -90,6 +90,9 @@ int Utils::RandomInt(const int min, const int max) return min + rand() % (max - min + 1); // <---- Limited randomness, but again } // sufficient for this use case +// Comparison used for cabin grouping (QuickSort): +// 1) cabinSize ascending +// 2) lastName alphabetical bool Utils::CompareLastnames(const TPerson *a, const TPerson *b) { if (a->cabinSize < b->cabinSize) @@ -117,10 +120,10 @@ int Utils::Partition(TPerson **arr, const int startIndex, const int endIndex) return i + 1; } -/// Time complexity **on average** is O(n log n) but worst case it O(n^2) -/// depending on where in the range the pivot lands -- If pivot is at either extreme -/// the algorithm has to search through the entire list for every value it sorts -- n^2 -/// However it does sort in-place, meaning no extra memory is needed +// QuickSort on an array of TPerson* using CompareLastnames: +// - Average time: O(n log n) +// - Worst case: O(n^2) if pivot choices are bad +// - Sorts in-place (no extra arrays) void Utils::QuickSort(TPerson** arr, const int low, const int high) { if (low < high) { @@ -130,8 +133,8 @@ void Utils::QuickSort(TPerson** arr, const int low, const int high) } } -/// Time complexity of the binary search is O(log n) -/// However the included fallback search is O(n) +// Binary search on an alphabetically sorted array of TPerson* (by lastName, then firstName). +// Primary search key: surname. If no surname match is found, falls back to linear scan on firstName. int Utils::BinarySearch(TPerson** arr, int p1, int p2, const std::string &target) { const int origStart = p1; @@ -153,9 +156,7 @@ int Utils::BinarySearch(TPerson** arr, int p1, int p2, const std::string &target p2 = newP - 1; } - /// Extra to search for firstname in the event that no matches were found - /// Disregard this section if you're purely looking at the - /// binary search understanding and implementation + // Fallback linear scan for first names if no last name match for (int i = origStart; i <= origEnd; i++) { if (arr[i]->firstName == target) return i;