Cleaning up and adding comments
This commit is contained in:
@@ -1,43 +1,38 @@
|
|||||||
// Option 1 (Standard): Console Text Editor.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "option1.h"
|
#include "option1.h"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include "SharedLib.h"
|
#include "SharedLib.h"
|
||||||
#include "TLinkedList.h"
|
#include "TLinkedList.h"
|
||||||
#include "TPerson.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()
|
int RunApp()
|
||||||
{
|
{
|
||||||
/* 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
|
// IMPORTANT: working directory must be set so that "DATA/random_names.txt" resolves correctly.
|
||||||
something like "C:\Users\Username\FolderYouSavedTheSubmissionIn\Exam\IKT203Exam\DATA\random_names.txt"
|
const std::string filename = "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";
|
|
||||||
|
|
||||||
pack("Reading names and grouping them.");
|
pack("Reading names and grouping them.");
|
||||||
// Call the utility function with the name callback
|
// Call the utility function with the name callback
|
||||||
readNamesFromFile(filename, onNameRead);
|
readNamesFromFile(filename, onNameRead);
|
||||||
|
|
||||||
pack("Finished reading names.");
|
pack("Finished reading names.");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////// Merge sorting ///////////////////////////
|
/////////////////////////// Merge sorting ///////////////////////////
|
||||||
|
// Sort both employee and guest linked lists alphabetically
|
||||||
|
// using the linked-list merge sort implementation in TLinkedList.
|
||||||
e.Sort();
|
e.Sort();
|
||||||
g.Sort();
|
g.Sort();
|
||||||
pack("Sorting.");
|
pack("Sorting.");
|
||||||
// Attempt at "beautifying" the terminal output somewhat
|
// Attempt at "beautifying" the terminal output somewhat
|
||||||
pack("Employees merge sorted alphabetically.");
|
pack("Employees merge sorted alphabetically.");
|
||||||
TPerson* employeeAlphaSort[e.GetSize()];
|
const int employeeSize = e.GetSize();
|
||||||
|
auto** employeeAlphaSort = new TPerson*[employeeSize];
|
||||||
printline();
|
printline();
|
||||||
for (int i = 0; i < e.GetSize(); i++) {
|
for (int i = 0; i < e.GetSize(); i++) {
|
||||||
std::cout << "[" << i << "] " << e.GetAtIndex(i).lastName << ", " << e.GetAtIndex(i).firstName
|
std::cout << "[" << i << "] " << e.GetAtIndex(i).lastName << ", " << e.GetAtIndex(i).firstName
|
||||||
@@ -45,8 +40,9 @@ int RunApp()
|
|||||||
employeeAlphaSort[i] = new TPerson(e.GetAtIndex(i));
|
employeeAlphaSort[i] = new TPerson(e.GetAtIndex(i));
|
||||||
}
|
}
|
||||||
printline();
|
printline();
|
||||||
pack("Guests merger sorted alphabetically.");
|
pack("Guests merge sorted alphabetically.");
|
||||||
TPerson* guestAlphaSort[g.GetSize()];
|
const int guestSize = g.GetSize();
|
||||||
|
auto** guestAlphaSort = new TPerson*[guestSize];
|
||||||
printline();
|
printline();
|
||||||
for (int i = 0; i < g.GetSize(); i++) {
|
for (int i = 0; i < g.GetSize(); i++) {
|
||||||
std::cout << "[" << i << "] " << g.GetAtIndex(i).lastName << ", " << g.GetAtIndex(i).firstName
|
std::cout << "[" << i << "] " << g.GetAtIndex(i).lastName << ", " << g.GetAtIndex(i).firstName
|
||||||
@@ -55,15 +51,15 @@ int RunApp()
|
|||||||
}
|
}
|
||||||
printline();
|
printline();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////// Quick sorting ///////////////////////////
|
/////////////////////////// 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
|
// creating array from guest linked list
|
||||||
auto** guestList = new TPerson*[guestCount];
|
auto** guestList = new TPerson*[guestCount];
|
||||||
for (int i = 0; i < guestCount; i++) {
|
for (int i = 0; i < guestCount; i++) {
|
||||||
guestList[i] = new TPerson(g.GetAtIndex(i));
|
guestList[i] = new TPerson(g.GetAtIndex(i));
|
||||||
}
|
}
|
||||||
// Quicksorting the guestlist array
|
|
||||||
Utils::QuickSort(guestList, 0, guestCount - 1);
|
Utils::QuickSort(guestList, 0, guestCount - 1);
|
||||||
|
|
||||||
pack("Guests quick sorted by 1) cabinsize, 2) lastname.");
|
pack("Guests quick sorted by 1) cabinsize, 2) lastname.");
|
||||||
@@ -74,19 +70,16 @@ int RunApp()
|
|||||||
}
|
}
|
||||||
printline();
|
printline();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////// Binary search ///////////////////////////
|
/////////////////////////// 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;
|
int choice;
|
||||||
std::string target;
|
std::string target;
|
||||||
std::cout << "What list do you want to search through: \n [1] Employee\n [2] Guest" << std::endl;
|
std::cout << "What list do you want to search through: \n [1] Employee\n [2] Guest" << std::endl;
|
||||||
std::cin >> choice;
|
std::cin >> choice;
|
||||||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||||
std::cout << "Enter surname to search: " << std::endl;
|
std::cout << "Enter name to search for: " << std::endl;
|
||||||
std::getline(std::cin, target);
|
std::getline(std::cin, target);
|
||||||
|
|
||||||
switch (choice) {
|
switch (choice) {
|
||||||
@@ -100,21 +93,31 @@ switch (choice) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////// Cleanup before exit ///////////////////////////
|
/////////////////////////// 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[i];
|
||||||
}
|
|
||||||
delete[] guestList;
|
delete[] guestList;
|
||||||
|
|
||||||
while (e.GetSize() > 0)
|
while (e.GetSize() > 0)
|
||||||
e.Remove(0);
|
e.Remove(0);
|
||||||
while (g.GetSize() > 0)
|
while (g.GetSize() > 0)
|
||||||
g.Remove(0);
|
g.Remove(0);
|
||||||
|
|
||||||
pack("Cleaned up memory");
|
pack("Cleaned up memory");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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
|
#pragma once
|
||||||
|
|
||||||
@@ -7,8 +9,13 @@
|
|||||||
#include "TLinkedList.h"
|
#include "TLinkedList.h"
|
||||||
#include "TPerson.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 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)
|
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 ENumStatus status = (aIndex < 1500) ? EMPLOYEE : GUEST;
|
||||||
|
|
||||||
const TPerson p(aFirstName, aLastName, status);
|
const TPerson p(aFirstName, aLastName, status);
|
||||||
@@ -64,7 +75,10 @@ static bool onNameRead(const int aIndex, const int aTotalCount, const std::strin
|
|||||||
return true;
|
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)
|
inline void SearchAndPrint(TPerson** targetArray, int arraySize, const std::string& target)
|
||||||
{
|
{
|
||||||
int index = Utils::BinarySearch(targetArray, 0, arraySize - 1, 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 left = index - 1;
|
||||||
int right = 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)) {
|
while (left >= 0 && (targetArray[left]->firstName == target || targetArray[left]->lastName == target)) {
|
||||||
--left;
|
--left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move right while neighbouring entries share the same first or last name
|
||||||
while (right < arraySize && (targetArray[right]->firstName == target || targetArray[right]->lastName == target)) {
|
while (right < arraySize && (targetArray[right]->firstName == target || targetArray[right]->lastName == target)) {
|
||||||
++right;
|
++right;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
#include "TAVL.h"
|
#include "TAVL.h"
|
||||||
|
|
||||||
#include <ios>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <bits/ios_base.h>
|
|
||||||
|
|
||||||
#include "TTreeQueue.h"
|
#include "TTreeQueue.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
@@ -57,7 +53,10 @@ AVLNode *TAVL::rotateLeft(AVLNode *x)
|
|||||||
return y;
|
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)
|
AVLNode *TAVL::insert(AVLNode *n, const int key)
|
||||||
{
|
{
|
||||||
if (!n)
|
if (!n)
|
||||||
@@ -74,23 +73,25 @@ AVLNode *TAVL::insert(AVLNode *n, const int key)
|
|||||||
|
|
||||||
if (balance > 1 && key < n->left->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);
|
return rotateRight(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (balance < -1 && key > n->right->key)
|
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);
|
return rotateLeft(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (balance > 1 && key > n->left->key)
|
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);
|
n->left = rotateLeft(n->left);
|
||||||
return rotateRight(n);
|
return rotateRight(n);
|
||||||
}
|
}
|
||||||
if (balance < -1 && key < n->right->key)
|
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);
|
n->right = rotateRight(n->right);
|
||||||
return rotateLeft(n);
|
return rotateLeft(n);
|
||||||
}
|
}
|
||||||
@@ -144,11 +145,17 @@ void TAVL::levelorder(const AVLNode* node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Public functions
|
// Public functions
|
||||||
|
///<summary> Insert node </summary
|
||||||
|
///<param name="key"> Node key value (int) </param>
|
||||||
|
/// <returns> None </returns>
|
||||||
void TAVL::Insert(const int key)
|
void TAVL::Insert(const int key)
|
||||||
{
|
{
|
||||||
root = insert(root, key);
|
root = insert(root, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> Inorder callback </summary
|
||||||
|
///<param name=""> AVLNode *node </param>
|
||||||
|
/// <returns> Bool </returns>
|
||||||
bool TAVL::Inorder(const AVLNode *node)
|
bool TAVL::Inorder(const AVLNode *node)
|
||||||
{
|
{
|
||||||
if (!node)
|
if (!node)
|
||||||
@@ -158,6 +165,9 @@ bool TAVL::Inorder(const AVLNode *node)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> Postorder callback </summary
|
||||||
|
///<param name=""> AVLNode *node </param>
|
||||||
|
/// <returns> Bool </returns>
|
||||||
bool TAVL::Postorder(const AVLNode *node)
|
bool TAVL::Postorder(const AVLNode *node)
|
||||||
{
|
{
|
||||||
if (!node)
|
if (!node)
|
||||||
@@ -167,6 +177,9 @@ bool TAVL::Postorder(const AVLNode *node)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> Preorder callback </summary
|
||||||
|
///<param name=""> AVLNode *node </param>
|
||||||
|
/// <returns> Bool </returns>
|
||||||
bool TAVL::Preorder(const AVLNode *node)
|
bool TAVL::Preorder(const AVLNode *node)
|
||||||
{
|
{
|
||||||
if (!node)
|
if (!node)
|
||||||
@@ -176,6 +189,9 @@ bool TAVL::Preorder(const AVLNode *node)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> LevelOrder callback </summary
|
||||||
|
///<param name=""> AVLNode *node </param>
|
||||||
|
/// <returns> Bool </returns>
|
||||||
bool TAVL::LevelOrder(const AVLNode *node)
|
bool TAVL::LevelOrder(const AVLNode *node)
|
||||||
{
|
{
|
||||||
if (!node)
|
if (!node)
|
||||||
@@ -185,6 +201,9 @@ bool TAVL::LevelOrder(const AVLNode *node)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> Prints the desired sorting order </summary
|
||||||
|
///<param name="cb"> Callback for the desired ordering algorithm (e.g. PrintOrder(LevelOrder) will print the Level Order algorithm to the terminal)</param>
|
||||||
|
/// <returns>None</returns>
|
||||||
void TAVL::PrintOrder(FOrderTraversal cb)
|
void TAVL::PrintOrder(FOrderTraversal cb)
|
||||||
{
|
{
|
||||||
if (!cb)
|
if (!cb)
|
||||||
@@ -192,6 +211,8 @@ void TAVL::PrintOrder(FOrderTraversal cb)
|
|||||||
cb(root);
|
cb(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to build an AVL tree with 'count' unique random keys
|
||||||
|
// in the range [minRange, maxRange]. Used only for demonstration in RunApp()
|
||||||
///<summary> Populates AVL tree </summary
|
///<summary> Populates AVL tree </summary
|
||||||
///<param name="avl"> The AVL tree to be populated</param>
|
///<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"count">How many elements to be populated into the tree</param>
|
||||||
@@ -205,7 +226,7 @@ void TAVL::Populate(TAVL* avl, const int count, const int minRange, const int ma
|
|||||||
int val = Utils::RandomInt(minRange, maxRange);
|
int val = Utils::RandomInt(minRange, maxRange);
|
||||||
while (AVLset.count(val))
|
while (AVLset.count(val))
|
||||||
val = Utils::RandomInt(minRange, maxRange);
|
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);
|
avl->Insert(val);
|
||||||
AVLset.insert(val);
|
AVLset.insert(val);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#ifndef IKT203_COURSE_ASSIGNMENTS_TAVL_H
|
#ifndef IKT203_COURSE_ASSIGNMENTS_TAVL_H
|
||||||
#define IKT203_COURSE_ASSIGNMENTS_TAVL_H
|
#define IKT203_COURSE_ASSIGNMENTS_TAVL_H
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
|
|
||||||
|
// Node used in the AVL tree.
|
||||||
|
// Stores only an integer key and height (no TEmployee data).
|
||||||
struct AVLNode {
|
struct AVLNode {
|
||||||
int key;
|
int key;
|
||||||
AVLNode* left;
|
AVLNode* left;
|
||||||
@@ -14,6 +14,8 @@ struct AVLNode {
|
|||||||
|
|
||||||
typedef bool (*FOrderTraversal)(const AVLNode* 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 {
|
class TAVL {
|
||||||
private:
|
private:
|
||||||
AVLNode* root;
|
AVLNode* root;
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#include "TBST.h"
|
#include "TBST.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "TTreeQueue.h"
|
#include "TTreeQueue.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -11,10 +9,15 @@ void TBST::destroy(BSTNode *node)
|
|||||||
return;
|
return;
|
||||||
destroy(node->left);
|
destroy(node->left);
|
||||||
destroy(node->right);
|
destroy(node->right);
|
||||||
|
// TBST owns the TEmployee* stored in each node, so delete it here.
|
||||||
delete node->data;
|
delete node->data;
|
||||||
delete node;
|
delete node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> Insert node </summary
|
||||||
|
///<param name="key"> Node key value (int) </param>
|
||||||
|
///<param name="data"> Employee data (TEmployee) </param>
|
||||||
|
/// <returns> None </returns>
|
||||||
void TBST::Insert(const int key, TEmployee *data)
|
void TBST::Insert(const int key, TEmployee *data)
|
||||||
{
|
{
|
||||||
root = insert(root, key, 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);
|
node->left = insert(node->left, key, data);
|
||||||
else if (key > node->key)
|
else if (key > node->key)
|
||||||
node->right = insert(node->right, key, data);
|
node->right = insert(node->right, key, data);
|
||||||
else
|
else {
|
||||||
std::cout << "Error with node insertion" << std::endl;
|
// 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;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> Search for node </summary
|
||||||
|
///<param name="key"> Node key value (int) </param>
|
||||||
|
/// <returns> TEmployee </returns>
|
||||||
TEmployee *TBST::Search(int key) const
|
TEmployee *TBST::Search(int key) const
|
||||||
{
|
{
|
||||||
const BSTNode* result = search(root, key);
|
const BSTNode* result = search(root, key);
|
||||||
@@ -54,6 +64,9 @@ BSTNode* TBST::search(BSTNode* node, const int key)
|
|||||||
return search(node->right, key);
|
return search(node->right, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> Delete node </summary
|
||||||
|
///<param name="key"> Node key value (int) </param>
|
||||||
|
/// <returns> None </returns>
|
||||||
void TBST::Delete(const int key)
|
void TBST::Delete(const int key)
|
||||||
{
|
{
|
||||||
root = remove(root, key);
|
root = remove(root, key);
|
||||||
@@ -88,7 +101,10 @@ BSTNode *TBST::remove(BSTNode *node, const int key)
|
|||||||
delete node;
|
delete node;
|
||||||
return child;
|
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 {
|
else {
|
||||||
BSTNode* minRight = findMin(node->right);
|
BSTNode* minRight = findMin(node->right);
|
||||||
node->key = minRight->key;
|
node->key = minRight->key;
|
||||||
@@ -106,8 +122,8 @@ BSTNode* TBST::findMin(BSTNode* node)
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Traversals
|
// Traversals
|
||||||
/// Private helpers
|
// Private helpers
|
||||||
void TBST::preorder(const BSTNode* node)
|
void TBST::preorder(const BSTNode* node)
|
||||||
{
|
{
|
||||||
if (!node)
|
if (!node)
|
||||||
@@ -153,24 +169,32 @@ void TBST::levelorder(const BSTNode* node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> Inorder sorting </summary
|
||||||
|
/// <returns> None </returns>
|
||||||
void TBST::Inorder() const
|
void TBST::Inorder() const
|
||||||
{
|
{
|
||||||
inorder(root);
|
inorder(root);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> Preorder sorting </summary
|
||||||
|
/// <returns> None </returns>
|
||||||
void TBST::Preorder() const
|
void TBST::Preorder() const
|
||||||
{
|
{
|
||||||
preorder(root);
|
preorder(root);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> Postorder sorting </summary
|
||||||
|
/// <returns> None </returns>
|
||||||
void TBST::Postorder() const
|
void TBST::Postorder() const
|
||||||
{
|
{
|
||||||
postorder(root);
|
postorder(root);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///<summary> LevelOrder sorting </summary
|
||||||
|
/// <returns> None </returns>
|
||||||
void TBST::LevelOrder() const
|
void TBST::LevelOrder() const
|
||||||
{
|
{
|
||||||
levelorder(root);
|
levelorder(root);
|
||||||
|
|||||||
@@ -2,13 +2,19 @@
|
|||||||
#define IKT203_COURSE_ASSIGNMENTS_TBST_H
|
#define IKT203_COURSE_ASSIGNMENTS_TBST_H
|
||||||
#include "TEmployee.h"
|
#include "TEmployee.h"
|
||||||
|
|
||||||
|
// Node in the Binary Search Tree.
|
||||||
|
// Owns a single TEmployee* which is deleted by TBST::destroy/remove.
|
||||||
struct BSTNode {
|
struct BSTNode {
|
||||||
int key;
|
int key; // employee ID
|
||||||
TEmployee* data;
|
TEmployee* data; // employee record
|
||||||
BSTNode* left;
|
BSTNode* left;
|
||||||
BSTNode* right;
|
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 {
|
class TBST {
|
||||||
private:
|
private:
|
||||||
BSTNode* root;
|
BSTNode* root;
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
// Simple employee record used in Category 3.
|
||||||
|
// 'id' is set later by IdGenerator and used as the BST key.
|
||||||
struct TEmployee {
|
struct TEmployee {
|
||||||
std::string firstName;
|
std::string firstName;
|
||||||
std::string lastName;
|
std::string lastName;
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
#define MAX_SIZE 200
|
#define MAX_SIZE 200
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "TBST.h"
|
#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 <typename T>
|
template <typename T>
|
||||||
struct TTreeQueue {
|
struct TTreeQueue {
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ struct TTreeQueue {
|
|||||||
void Enqueue(T* n)
|
void Enqueue(T* n)
|
||||||
{
|
{
|
||||||
if (n == nullptr)
|
if (n == nullptr)
|
||||||
return;
|
return; // ignore null pointers, nothing to enqueue
|
||||||
if (IsFull())
|
if (IsFull())
|
||||||
throw std::overflow_error("Queue Overflow");
|
throw std::overflow_error("Queue Overflow");
|
||||||
queue[tail] = n;
|
queue[tail] = n;
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
#include "option1.h"
|
#include "option1.h"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
// 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() {
|
int RunApp() {
|
||||||
//Reading names from file for BST population
|
//Reading names from file for BST population
|
||||||
bst = new TBST();
|
bst = new TBST();
|
||||||
/* Path to the names data file
|
|
||||||
This is MY absolute path -- change to your local path for this to read properly
|
// Read 200 employees from the names file and populate the BST.
|
||||||
something like "C:\Users\Username\FolderYouSavedTheSubmissionIn\Exam\IKT203Exam\DATA\random_names.txt"
|
// IMPORTANT: Working directory must be the Portfolio/Assignment-03 folder
|
||||||
Double slash is needed for string to pass the correct file path */
|
// so that "DATA/random_names.txt" resolves correctly.
|
||||||
const std::string filename = "C:\\Users\\csand\\IKT203\\Exam\\IKT203Exam\\DATA\\random_names.txt";
|
const std::string filename = "DATA/random_names.txt";
|
||||||
readNamesFromFile(filename, onNameRead);
|
readNamesFromFile(filename, onNameRead);
|
||||||
|
|
||||||
// BST traversal -- comment out the entire block
|
// --- BST traversals ---
|
||||||
// when done inspecting for more manageable terminal output
|
// 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)");
|
pack("Inorder traversal (sorted by ID)");
|
||||||
bst->Inorder();
|
bst->Inorder();
|
||||||
|
|
||||||
@@ -26,6 +32,8 @@ int RunApp() {
|
|||||||
pack("Postorder traversal");
|
pack("Postorder traversal");
|
||||||
bst->Postorder();
|
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");
|
pack("Search function");
|
||||||
std::cout << "\nInput the ID you want to search for\n" << std::endl;
|
std::cout << "\nInput the ID you want to search for\n" << std::endl;
|
||||||
int choice;
|
int choice;
|
||||||
@@ -36,6 +44,9 @@ int RunApp() {
|
|||||||
else
|
else
|
||||||
std::cout << "ID not found" << std::endl;
|
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");
|
pack("Remove function");
|
||||||
std::cout << "\nInput the ID you want to remove\n" << std::endl;
|
std::cout << "\nInput the ID you want to remove\n" << std::endl;
|
||||||
std::cin >> choice;
|
std::cin >> choice;
|
||||||
@@ -49,13 +60,13 @@ int RunApp() {
|
|||||||
bst->Inorder();
|
bst->Inorder();
|
||||||
// End of BST block
|
// End of BST block
|
||||||
|
|
||||||
// Start of AVL block
|
// --- AVL demo ---
|
||||||
// Again, comment out the block if terminal output is
|
// Build an AVL tree using random integers in [1, 200].
|
||||||
// too noisy
|
// This tree only stores keys (no TEmployee data) and is used
|
||||||
|
// to demonstrate balancing and traversals.
|
||||||
pack("AVL");
|
pack("AVL");
|
||||||
avl = new TAVL;
|
avl = new TAVL;
|
||||||
|
|
||||||
|
|
||||||
TAVL::Populate(avl, 100, 1, 200);
|
TAVL::Populate(avl, 100, 1, 200);
|
||||||
pack("Inorder");
|
pack("Inorder");
|
||||||
avl->PrintOrder(TAVL::Inorder);
|
avl->PrintOrder(TAVL::Inorder);
|
||||||
@@ -71,9 +82,9 @@ int RunApp() {
|
|||||||
// End of AVL block
|
// End of AVL block
|
||||||
|
|
||||||
|
|
||||||
// Cleaning to free up memory.
|
// --- Cleanup ---
|
||||||
// Used only at end of runtime, but useful for when runtime needs
|
// TBST destructor deletes all TEmployee objects it owns.
|
||||||
// to be continuous
|
// Here we delete the tree objects themselves to avoid leaks.
|
||||||
pack ("Cleaning up");
|
pack ("Cleaning up");
|
||||||
delete bst;
|
delete bst;
|
||||||
delete avl;
|
delete avl;
|
||||||
|
|||||||
@@ -3,25 +3,24 @@
|
|||||||
#ifndef OPTION1_H
|
#ifndef OPTION1_H
|
||||||
#define OPTION1_H
|
#define OPTION1_H
|
||||||
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <TTreeQueue.h>
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "TAVL.h"
|
#include "TAVL.h"
|
||||||
#include "TBST.h"
|
#include "TBST.h"
|
||||||
#include "TEmployee.h"
|
#include "TEmployee.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "../../Submissions/Submission-04/BankAccount.h"
|
|
||||||
|
|
||||||
/// To keep track of used ID values to ensure
|
// Global state for Category 3, Option 1:
|
||||||
/// all unique IDs
|
// - 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<int> usedIds;
|
inline std::unordered_set<int> usedIds;
|
||||||
static TBST* bst;
|
static TBST* bst;
|
||||||
static TAVL* avl;
|
static TAVL* avl;
|
||||||
|
|
||||||
int RunApp();
|
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)
|
inline void IdGenerator(TEmployee* employee)
|
||||||
{
|
{
|
||||||
int id = Utils::RandomInt(1, 1000);
|
int id = Utils::RandomInt(1, 1000);
|
||||||
@@ -32,6 +31,11 @@ inline void IdGenerator(TEmployee* employee)
|
|||||||
usedIds.insert(id);
|
usedIds.insert(id);
|
||||||
employee->id = 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)
|
static bool onNameRead(const int index, const int aTotalCount, const std::string& aFirstName, const std::string& aLastName)
|
||||||
{
|
{
|
||||||
const auto e = new TEmployee(aFirstName, aLastName);
|
const auto e = new TEmployee(aFirstName, aLastName);
|
||||||
@@ -50,6 +54,7 @@ inline void printline()
|
|||||||
std::cout << "----------------------------------------" << std::endl;
|
std::cout << "----------------------------------------" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to visually separate different demos (traversals, search, etc.) in the console output.
|
||||||
inline void pack(const std::string& line)
|
inline void pack(const std::string& line)
|
||||||
{
|
{
|
||||||
std::cout << "\n\n\n" << std::endl;
|
std::cout << "\n\n\n" << std::endl;
|
||||||
|
|||||||
@@ -149,8 +149,8 @@ TLinkedList::Node *TLinkedList::MergeList(Node *a, Node *b)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Time complexity O(n log n) at all times
|
// Time complexity O(n log n) at all times
|
||||||
/// Does NOT sort in place, so more memory is needed to complete
|
// Does NOT sort in place, so more memory is needed to complete
|
||||||
TLinkedList::Node *TLinkedList::MergeSort(Node *head)
|
TLinkedList::Node *TLinkedList::MergeSort(Node *head)
|
||||||
{
|
{
|
||||||
if (head == nullptr || head->next == nullptr)
|
if (head == nullptr || head->next == nullptr)
|
||||||
@@ -166,6 +166,8 @@ TLinkedList::Node *TLinkedList::MergeSort(Node *head)
|
|||||||
return MergeList(front, back);
|
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()
|
void TLinkedList::Sort()
|
||||||
{
|
{
|
||||||
this->head = MergeSort(head);
|
this->head = MergeSort(head);
|
||||||
|
|||||||
@@ -3,12 +3,15 @@
|
|||||||
|
|
||||||
#include "TPerson.h"
|
#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 {
|
class TLinkedList {
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Node {
|
struct Node {
|
||||||
TPerson person;
|
TPerson person; // stored by value
|
||||||
Node* next;
|
Node* next;
|
||||||
explicit Node(const TPerson& p) : person(p), next(nullptr) {}
|
explicit Node(const TPerson& p) : person(p), next(nullptr) {}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ enum ENumStatus {
|
|||||||
EMPLOYEE
|
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 {
|
struct TPerson {
|
||||||
std::string firstName;
|
std::string firstName;
|
||||||
std::string lastName;
|
std::string lastName;
|
||||||
@@ -20,6 +22,8 @@ struct TPerson {
|
|||||||
TPerson(std::string , std::string , ENumStatus);
|
TPerson(std::string , std::string , ENumStatus);
|
||||||
~TPerson() = default;
|
~TPerson() = default;
|
||||||
|
|
||||||
|
// Comparison for alphabetical sorting:
|
||||||
|
// primary key: lastName, secondary key: firstName.
|
||||||
bool operator<(const TPerson& other) const
|
bool operator<(const TPerson& other) const
|
||||||
{
|
{
|
||||||
if (lastName < other.lastName) return true;
|
if (lastName < other.lastName) return true;
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ int Utils::RandomInt(const int min, const int max)
|
|||||||
return min + rand() % (max - min + 1); // <---- Limited randomness, but again
|
return min + rand() % (max - min + 1); // <---- Limited randomness, but again
|
||||||
} // sufficient for this use case
|
} // 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)
|
bool Utils::CompareLastnames(const TPerson *a, const TPerson *b)
|
||||||
{
|
{
|
||||||
if (a->cabinSize < b->cabinSize)
|
if (a->cabinSize < b->cabinSize)
|
||||||
@@ -117,10 +120,10 @@ int Utils::Partition(TPerson **arr, const int startIndex, const int endIndex)
|
|||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Time complexity **on average** is O(n log n) but worst case it O(n^2)
|
// QuickSort on an array of TPerson* using CompareLastnames:
|
||||||
/// depending on where in the range the pivot lands -- If pivot is at either extreme
|
// - Average time: O(n log n)
|
||||||
/// the algorithm has to search through the entire list for every value it sorts -- n^2
|
// - Worst case: O(n^2) if pivot choices are bad
|
||||||
/// However it does sort in-place, meaning no extra memory is needed
|
// - Sorts in-place (no extra arrays)
|
||||||
void Utils::QuickSort(TPerson** arr, const int low, const int high)
|
void Utils::QuickSort(TPerson** arr, const int low, const int high)
|
||||||
{
|
{
|
||||||
if (low < 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)
|
// Binary search on an alphabetically sorted array of TPerson* (by lastName, then firstName).
|
||||||
/// However the included fallback search is O(n)
|
// 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)
|
int Utils::BinarySearch(TPerson** arr, int p1, int p2, const std::string &target)
|
||||||
{
|
{
|
||||||
const int origStart = p1;
|
const int origStart = p1;
|
||||||
@@ -153,9 +156,7 @@ int Utils::BinarySearch(TPerson** arr, int p1, int p2, const std::string &target
|
|||||||
p2 = newP - 1;
|
p2 = newP - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extra to search for firstname in the event that no matches were found
|
// Fallback linear scan for first names if no last name match
|
||||||
/// Disregard this section if you're purely looking at the
|
|
||||||
/// binary search understanding and implementation
|
|
||||||
for (int i = origStart; i <= origEnd; i++) {
|
for (int i = origStart; i <= origEnd; i++) {
|
||||||
if (arr[i]->firstName == target)
|
if (arr[i]->firstName == target)
|
||||||
return i;
|
return i;
|
||||||
|
|||||||
Reference in New Issue
Block a user