commit 0360e7dfccd0cd48514e4e66626f524b01767faa Author: jslightham Date: Sun May 21 23:28:11 2023 -0400 Initial commit diff --git a/P1/Calculator.cpp b/P1/Calculator.cpp new file mode 100644 index 0000000..23f9c75 --- /dev/null +++ b/P1/Calculator.cpp @@ -0,0 +1,62 @@ +#include "Calculator.h" +#include "VariableNode.h" + +using namespace std; + +Calculator::Calculator(int cap) +{ + this->data = new VariableLinkedList(cap); +} + +Calculator::~Calculator() +{ + delete this->data; +} + +/// @brief Define a new variable +/// @param name The name of the new variable +/// @param value The initial value to store in the variable +/// @return True if the variable was added, false otherwise +bool Calculator::define(string name, double value) +{ + return this->data->insert(name, value); +} + +/// @brief Perform an operation on two variables, and store the result in a thrid +/// @param v1 The first variable to perform the operation on +/// @param v2 The second variable to perform the opetation on +/// @param v3 The variable to store the output result in +/// @param operation A lambda function to apply on the two variables +/// @return True if successful, false otherwise +bool Calculator::performOperation(string v1, string v2, string out, function operation) +{ + VariableNode *vn1 = this->data->search(v1); + VariableNode *vn2 = this->data->search(v2); + VariableNode *output = this->data->search(out); + + // If a single one of the variables is not found, we cannot continue. + if (vn1 == nullptr || vn2 == nullptr || output == nullptr) + return false; + + output->setValue(operation(vn1->getValue(), vn2->getValue())); + return true; +} + +/// @brief Remove the given variable from storage +/// @param name The name of the variable to remove +/// @return True if the variable was successfully removed, false otherwise +bool Calculator::remove(string name) +{ + return this->data->remove(name); +} + +/// @brief Print out the value of the given variable +/// @param name The name of the variable to print out +void Calculator::print(string name) +{ + VariableNode *temp = this->data->search(name); + if (temp == nullptr) + cout << "variable " << name << " not found" << endl; + else + cout << temp->getValue() << endl; +} diff --git a/P1/Calculator.h b/P1/Calculator.h new file mode 100644 index 0000000..b002a7b --- /dev/null +++ b/P1/Calculator.h @@ -0,0 +1,22 @@ +#ifndef CALCULATOR_H +#define CALCULATOR_H + +#include +#include +#include "VariableNode.h" +#include "VariableLinkedList.h" + +class Calculator +{ +public: + bool define(std::string name, double value); + bool performOperation(std::string v1, std::string v2, std::string output, std::function operation); + bool remove(std::string name); + void print(std::string name); + Calculator(int cap); + ~Calculator(); + +private: + VariableLinkedList *data; +}; +#endif diff --git a/P1/Makefile b/P1/Makefile new file mode 100644 index 0000000..b2f8fef --- /dev/null +++ b/P1/Makefile @@ -0,0 +1,2 @@ +all: test.cpp Calculator.cpp VariableNode.cpp VariableLinkedList.cpp + g++ -std=c++11 test.cpp Calculator.cpp VariableNode.cpp VariableLinkedList.cpp \ No newline at end of file diff --git a/P1/VariableLinkedList.cpp b/P1/VariableLinkedList.cpp new file mode 100644 index 0000000..6b3a31c --- /dev/null +++ b/P1/VariableLinkedList.cpp @@ -0,0 +1,88 @@ +#include "VariableLinkedList.h" + +using namespace std; + +VariableLinkedList::VariableLinkedList(int cap) +{ + this->maxCount = cap; + this->count = 0; + this->head = nullptr; +} + +VariableLinkedList::~VariableLinkedList() +{ + if (head != nullptr) + head->DestroyAll(); +} + +/// @brief Insert a variable into the head of the linked list +/// @param name The name of the variable to insert +/// @param value The double value to initialize the variable with +/// @return True if the variable was added, false otherwise +bool VariableLinkedList::insert(string name, double value) +{ + // Ensure there is space + if (count == maxCount) + return false; + + // Ensure the variable does not exist + VariableNode *s = this->search(name); + if (s != nullptr) + return false; + + // Insert a new VariableNode into the head. + head = new VariableNode(name, value, head); + + count++; + return true; +} + +/// @brief Remove the variable with name from the linked list +/// @param name The name of the variable to remove +/// @return True if removed, false otherwise +bool VariableLinkedList::remove(string name) +{ + // Root node must be handled in a seperate case + if (head != nullptr && head->getName() == name) + { + VariableNode *temp = head->getNext(); + delete head; + head = temp; + count --; + return true; + } + + // Search for the node before the one we want to remove. + VariableNode *currentIndex = this->head; + while (currentIndex != nullptr && currentIndex->getNext() != nullptr && + currentIndex->getNext()->getName() != name) + currentIndex = currentIndex->getNext(); + + // currentIndex will be null if the index does not exist. + if (currentIndex == nullptr || currentIndex->getNext() == nullptr) + return false; + + VariableNode *temp = currentIndex->getNext()->getNext(); + delete currentIndex->getNext(); + count--; + currentIndex->setNext(temp); + return true; +} + +/// @brief Search for the variable with the given name +/// @param name The name of the variable to search for +/// @return A pointer to a valid VariableNode if the node exists, nullptr otherwise +VariableNode *VariableLinkedList::search(string name) +{ + VariableNode *currentIndex = this->head; + while (currentIndex != nullptr) + { + if (currentIndex->getName() == name) + { + return currentIndex; + } + currentIndex = currentIndex->getNext(); + } + + return nullptr; +} diff --git a/P1/VariableLinkedList.h b/P1/VariableLinkedList.h new file mode 100644 index 0000000..14f62b0 --- /dev/null +++ b/P1/VariableLinkedList.h @@ -0,0 +1,22 @@ +#ifndef VARIABLELINKEDLIST_H +#define VARIABLELINKEDLIST_H + +#include +#include +#include "VariableNode.h" + +class VariableLinkedList +{ +public: + bool insert(std::string name, double value); + VariableNode *search(std::string name); + bool remove(std::string name); + VariableLinkedList(int cap); + ~VariableLinkedList(); + +private: + VariableNode *head; + int count; + int maxCount; +}; +#endif diff --git a/P1/VariableNode.cpp b/P1/VariableNode.cpp new file mode 100644 index 0000000..f18bf19 --- /dev/null +++ b/P1/VariableNode.cpp @@ -0,0 +1,44 @@ +#include "VariableNode.h" + +using namespace std; + +VariableNode::VariableNode(std::string name, double value, VariableNode *next) +{ + this->name = name; + this->value = value; + this->next = next; +} + +string VariableNode::getName() +{ + return name; +} + +double VariableNode::getValue() +{ + return value; +} + +void VariableNode::setValue(double value) +{ + this->value = value; +} + +void VariableNode::setNext(VariableNode *next) +{ + this->next = next; // Be careful when calling setNext, or we could have a memory leak. +} + +VariableNode *VariableNode::getNext() +{ + return next; +} + +/// @brief Delete all children nodes of this element +void VariableNode::DestroyAll() +{ + if (this->next != nullptr) + this->next->DestroyAll(); + + delete this; +} diff --git a/P1/VariableNode.h b/P1/VariableNode.h new file mode 100644 index 0000000..7946fd6 --- /dev/null +++ b/P1/VariableNode.h @@ -0,0 +1,26 @@ +#ifndef VARIABLENODE_H +#define VARIABLENODE_H + +#include + +class VariableNode +{ +public: + std::string getName(); + + double getValue(); + void setValue(double value); + + VariableNode *getNext(); + void setNext(VariableNode *next); + + VariableNode(std::string name, double value, VariableNode *next); + + void DestroyAll(); + +private: + std::string name; + double value; + VariableNode *next; +}; +#endif \ No newline at end of file diff --git a/P1/test.cpp b/P1/test.cpp new file mode 100644 index 0000000..8b95019 --- /dev/null +++ b/P1/test.cpp @@ -0,0 +1,92 @@ +#include +#include "Calculator.h" + +using namespace std; + +int main () +{ + string cmd; + Calculator *calc = nullptr; + + while (cin >> cmd) + { + if (cmd == "CRT") + { + int N; + cin >> N; + + if (calc != nullptr) + delete calc; + calc = new Calculator(N); + + cout << "success" << endl; + } + else if (cmd == "DEF") + { + string name; + double val; + + cin >> name; + cin >> val; + + if (calc->define(name, val)) + { + cout << "success" << endl; + } + else + { + cout << "failure" << endl; + } + } + else if (cmd == "ADD" || cmd == "SUB") + { + string v1; + string v2; + string out; + + cin >> v1; + cin >> v2; + cin >> out; + + function operation; + if (cmd == "ADD") + operation = [](double d1, double d2) {return d1 + d2;}; + else + operation = [](double d1, double d2) {return d1 - d2;}; + + if (calc->performOperation(v1, v2, out, operation)) + { + cout << "success" << endl; + } + else + { + cout << "failure" << endl; + } + } + else if (cmd == "REM") + { + string name; + + cin >> name; + + if (calc->remove(name)) + cout << "success" << endl; + else + cout << "failure" << endl; + } + else if (cmd == "PRT") + { + string name; + + cin >> name; + + calc->print(name); + } + else if (cmd == "END") + { + break; + } + } + + delete calc; +} \ No newline at end of file diff --git a/P2/ChainingHashTable.cpp b/P2/ChainingHashTable.cpp new file mode 100644 index 0000000..b29da12 --- /dev/null +++ b/P2/ChainingHashTable.cpp @@ -0,0 +1,156 @@ +#include + +#include "ChainingHashTable.h" +#include "Process.h" + +ChainingHashTable::ChainingHashTable(int size) +{ + processList = new std::vector[size]; + maxCount = size; + count = 0; +} + +ChainingHashTable::~ChainingHashTable() +{ + for (int i = 0; i < maxCount; i++) + { + for (int j = 0; j < processList[i].size(); j++) + { + delete processList[i][j]; + } + } + + delete[] processList; +} + +/// @brief Insert a process into the hash table +/// @param p the process to insert +/// @return true if insertion was successful, false otherwise +bool ChainingHashTable::Insert(Process *p) +{ + if (count >= maxCount) + { + return false; + } + + int hashedIndex = p->getPid() % maxCount; + + int indexSize = processList[hashedIndex].size(); + + if (indexSize == 0) + { + processList[hashedIndex].emplace_back(p); + count++; + return true; + } + + // attempt to insert in the middle of the vector + for (int i = 0; i < indexSize; i++) + { + if (processList[hashedIndex][i]->getPid() == p->getPid()) + { + return false; + } + // store in descending order (9, 8, 7,...) + if (processList[hashedIndex][i]->getPid() < p->getPid()) + { + processList[hashedIndex].insert(processList[hashedIndex].begin() + i, p); + count++; + return true; + } + } + + // insert at the end of the vector if we have to + processList[hashedIndex].emplace_back(p); + return true; +} + +/// @brief Search the hash table for the PID +/// @param PID the PID to search the hash table for +/// @return the index if in the hash table, or -1 otherwise +int ChainingHashTable::Search(unsigned int PID) +{ + int hashedIndex = PID % maxCount; + + int indexSize = processList[hashedIndex].size(); + + for (int i = 0; i < indexSize; i++) + { + if (processList[hashedIndex][i]->getPid() == PID) + { + return hashedIndex; + } + } + + return -1; +} + +/// @brief Get a pointer to the process with PID +/// @param PID the PID to look for +/// @return a pointer to the process, or nullptr if the process does not exist +Process *ChainingHashTable::Get(unsigned int PID) +{ + int hashedIndex = PID % maxCount; + + int indexSize = processList[hashedIndex].size(); + + for (int i = 0; i < indexSize; i++) + { + if (processList[hashedIndex][i]->getPid() == PID) + { + return processList[hashedIndex][i]; + } + } + + return nullptr; +} + +/// @brief Remove a process from the hash table with a given PID +/// @param PID the PID of the process to remove +/// @return true if the process was removed, false otherwise +bool ChainingHashTable::Remove(unsigned int PID) +{ + int hashedIndex = PID % maxCount; + + int indexSize = processList[hashedIndex].size(); + + for (int i = 0; i < indexSize; i++) + { + if (processList[hashedIndex][i]->getPid() == PID) + { + delete processList[hashedIndex][i]; + processList[hashedIndex].erase(processList[hashedIndex].begin() + i); + count--; + return true; + } + } + return false; +} + +/// @brief Print out the value of the chain at index m +/// @param m the index to print the chain of +void ChainingHashTable::Print(unsigned int m) +{ + if (m >= maxCount) + { + std::cout << "chain is empty" << std::endl; + return; + } + + int indexSize = processList[m].size(); + + for (int i = 0; i < indexSize; i++) + { + if (i != 0) + std::cout << " "; + + std::cout << processList[m][i]->getPid(); + } + + if (indexSize < 1) + { + std::cout << "chain is empty"; + } + + std::cout << std::endl; +} diff --git a/P2/ChainingHashTable.h b/P2/ChainingHashTable.h new file mode 100644 index 0000000..87350ea --- /dev/null +++ b/P2/ChainingHashTable.h @@ -0,0 +1,23 @@ +#ifndef CHAININGHASHTABLE_H +#define CHAININGHASHTABLE_H + +#include +#include "Process.h" +#include "HashTable.h" + +class ChainingHashTable : public HashTable +{ +public: + bool Insert(Process *p); + int Search(unsigned int PID); + Process *Get(unsigned int PID); + bool Remove(unsigned int PID); + void Print(unsigned int m); + + ChainingHashTable(int size); + ~ChainingHashTable(); + +private: + std::vector *processList; +}; +#endif diff --git a/P2/DoubleHashTable.cpp b/P2/DoubleHashTable.cpp new file mode 100644 index 0000000..53279dd --- /dev/null +++ b/P2/DoubleHashTable.cpp @@ -0,0 +1,177 @@ + +#include +#include + +#include "DoubleHashTable.h" +#include "Process.h" + +DoubleHashTable::DoubleHashTable(int size) +{ + processList = new Process *[size]; + maxCount = size; + count = 0; + + for (int i = 0; i < size; i++) + { + processList[i] = nullptr; + } +} + +DoubleHashTable::~DoubleHashTable() +{ + for (int i = 0; i < maxCount; i++) + { + if (processList[i] != nullptr) + delete processList[i]; + } + + delete[] processList; +} + +/// @brief Insert a process into the hash table +/// @param p pointer to the process to insert +/// @return true if successful, false otherwise +bool DoubleHashTable::Insert(Process *p) +{ + if (count >= maxCount) + { + return false; + } + + // Continually hash until we have reached a nullpointer, -1, or the end + int emptyIndex = -1; + for (int i = 0; i < maxCount; i++) + { + unsigned int hashedIndex = HashIndex(p->getPid(), i); + + // If we have reached a nullptr, and have not seen any empty slots before + if (processList[hashedIndex] == nullptr && emptyIndex == -1) + { + // Replace the nullpointer with the process + processList[hashedIndex] = p; + return true; + } + // If we have reached a nullpointer and have seen an empty slot before + else if (processList[hashedIndex] == nullptr && emptyIndex != -1) + { + // Replace the -1 with the process + hashedIndex = HashIndex(p->getPid(), emptyIndex); + delete processList[hashedIndex]; + processList[hashedIndex] = p; + return true; + } + // If we find a process with the same PID already, exit + else if (processList[hashedIndex]->getPid() == p->getPid()) + { + return false; + } + // If we have found a slot of -1 + else if (processList[hashedIndex]->getStartingIndex() == -1 && emptyIndex == -1) + { + // If we can insert in the empty slot (have reached the end) + emptyIndex = i; + if (!(i + 1 < maxCount)) + { + delete processList[hashedIndex]; + processList[hashedIndex] = p; + return true; + } + } + } + + // Insert into the empty slot - theoretically we do not need the code in the if statement of the last else if clause, but it works... + if (emptyIndex != -1) + { + unsigned int hashedIndex = HashIndex(p->getPid(), emptyIndex); + delete processList[hashedIndex]; + processList[hashedIndex] = p; + return true; + } + + return false; +} + +/// @brief Search the hash table for the given PID +/// @param PID the pid to search for +/// @return the index of the process, or -1 if the process does not exist +int DoubleHashTable::Search(unsigned int PID) +{ + for (int i = 0; i < maxCount; i++) + { + int hashedIndex = HashIndex(PID, i); + + if (hashedIndex >= maxCount || processList[hashedIndex] == nullptr) + { + return -1; + } + else if (processList[hashedIndex]->getPid() == PID) + { + return hashedIndex; + } + } + return -1; +} + +/// @brief Search the hash table for the given PID, and return a pointer to the process object +/// @param PID the pid to search for +/// @return A valid process object if it exists, or a nullpointer otherwise +Process *DoubleHashTable::Get(unsigned int PID) +{ + for (int i = 0; i < maxCount; i++) + { + int hashedIndex = HashIndex(PID, i); + + if (hashedIndex >= maxCount || processList[hashedIndex] == nullptr) + { + return nullptr; + } + else if (processList[hashedIndex]->getPid() == PID) + { + return processList[hashedIndex]; + } + } + return nullptr; +} + +/// @brief Remove a process object from the hash table +/// @param PID the PID of the process to remove +/// @return true if the process was successfully removed, false otherwise +bool DoubleHashTable::Remove(unsigned int PID) +{ + for (int i = 0; i < maxCount; i++) + { + int hashedIndex = HashIndex(PID, i); + + if (hashedIndex >= maxCount || processList[hashedIndex] == nullptr) + { + return false; + } + else if (processList[hashedIndex]->getPid() == PID) + { + delete processList[hashedIndex]; + processList[hashedIndex] = new Process(0, -1); + return true; + } + } + return false; +} + +/// @brief Compute the hash of k and i. +/// @param k the k value to hash (PID) +/// @param i the i value to hash (index) +/// @return the hashed value +int DoubleHashTable::HashIndex(unsigned int k, int i) +{ + unsigned int h1 = k % maxCount; + unsigned int h2 = (int)std::floor(k / maxCount) % maxCount; + + if (h2 % 2 == 0) + h2++; + + return (h1 + i * h2) % maxCount; +} + +void DoubleHashTable::Print(unsigned int m) +{ + // Not implemented +} diff --git a/P2/DoubleHashTable.h b/P2/DoubleHashTable.h new file mode 100644 index 0000000..35861a0 --- /dev/null +++ b/P2/DoubleHashTable.h @@ -0,0 +1,24 @@ +#ifndef DOUBLEHASHTABLE_H +#define DOUBLEHASHTABLE_H + +#include +#include "Process.h" +#include "HashTable.h" + +class DoubleHashTable : public HashTable +{ +public: + bool Insert(Process *p); + int Search(unsigned int PID); + Process *Get(unsigned int PID); + bool Remove(unsigned int PID); + void Print(unsigned int m); + + DoubleHashTable(int size); + ~DoubleHashTable(); + +private: + Process **processList; + int HashIndex(unsigned int k, int i); +}; +#endif diff --git a/P2/HashTable.h b/P2/HashTable.h new file mode 100644 index 0000000..099e920 --- /dev/null +++ b/P2/HashTable.h @@ -0,0 +1,20 @@ +#ifndef HASHTABLE_H +#define HASHTABLE_H + +#include +#include "Process.h" + +class HashTable +{ +public: + virtual bool Insert(Process *p) = 0; + virtual int Search(unsigned int PID) = 0; + virtual Process *Get(unsigned int PID) = 0; + virtual bool Remove(unsigned int PID) = 0; + virtual void Print(unsigned int m) = 0; + +protected: + int maxCount; + int count; +}; +#endif diff --git a/P2/Makefile b/P2/Makefile new file mode 100644 index 0000000..2628b83 --- /dev/null +++ b/P2/Makefile @@ -0,0 +1,2 @@ +all: test.cpp ChainingHashTable.cpp DoubleHashTable.cpp Process.cpp VirtualMemory.cpp + g++ -std=c++11 test.cpp ChainingHashTable.cpp DoubleHashTable.cpp Process.cpp VirtualMemory.cpp \ No newline at end of file diff --git a/P2/Process.cpp b/P2/Process.cpp new file mode 100644 index 0000000..9f2f3b6 --- /dev/null +++ b/P2/Process.cpp @@ -0,0 +1,17 @@ +#include "Process.h" + +Process::Process(unsigned int PID, int startingIndex) +{ + this->PID = PID; + this->startingIndex = startingIndex; +} + +unsigned int Process::getPid() +{ + return this->PID; +} + +int Process::getStartingIndex() +{ + return this->startingIndex; +} diff --git a/P2/Process.h b/P2/Process.h new file mode 100644 index 0000000..15e068e --- /dev/null +++ b/P2/Process.h @@ -0,0 +1,16 @@ +#ifndef PROCESS_H +#define PROCESS_H + +class Process +{ +public: + unsigned int getPid(); + int getStartingIndex(); + + Process(unsigned int PID, int startingIndex); + +private: + unsigned int PID; + int startingIndex; +}; +#endif diff --git a/P2/VirtualMemory.cpp b/P2/VirtualMemory.cpp new file mode 100644 index 0000000..4e8f8e6 --- /dev/null +++ b/P2/VirtualMemory.cpp @@ -0,0 +1,136 @@ +#include + +#include "VirtualMemory.h" +#include "ChainingHashTable.h" +#include "DoubleHashTable.h" + +VirtualMemory::VirtualMemory(int n, int p, bool chaining) +{ + if (chaining) + { + ht = new ChainingHashTable(n / p); + } + else + { + ht = new DoubleHashTable(n / p); + } + + this->chaining = chaining; + this->memorySize = n; + this->pageSize = p; + this->memory = new int[n]; + + // push the indices onto the free memory + for (int i = 0; i < n / p; i++) + { + freeMemory.push_back(i); + } +} + +VirtualMemory::~VirtualMemory() +{ + if (chaining) + { + delete (ChainingHashTable *)ht; + } + else + { + delete (DoubleHashTable *)ht; + } + + delete[] memory; +} + +/// @brief Allocate memory for process PID +/// @param PID the PID to allocate memory for +/// @return true if successful, false otherwise +bool VirtualMemory::Insert(unsigned int PID) +{ + if (freeMemory.size() <= 0) + return false; + + int memoryIndex = freeMemory.back(); + freeMemory.pop_back(); + + Process *p = new Process(PID, memoryIndex); + if (!ht->Insert(p)) + { + delete p; + freeMemory.push_back(memoryIndex); + return false; + } + + return true; +} + +/// @brief Search the hash table for the index of PID +/// @param PID the PID of the process to search for +/// @return the index of the process object, -1 if the object does not exist +int VirtualMemory::Search(unsigned int PID) +{ + return ht->Search(PID); +} + +/// @brief Write to a process's memory +/// @param PID The PID of the memory to write to +/// @param addr The virtual address of the memory to write to +/// @param x The value to write into memory +/// @return true if successful, false otherwise +bool VirtualMemory::Write(unsigned int PID, int addr, int x) +{ + if (addr >= pageSize || addr < 0) + return false; + + Process *p = ht->Get(PID); + + // if we do not have any memory allocated to PID + if (p == nullptr) + return false; + + memory[p->getStartingIndex() * pageSize + addr] = x; + return true; +} + +/// @brief Read the memory +/// @param PID The PID of the process to read memory of +/// @param addr The virtual address of memory to read from +void VirtualMemory::Read(unsigned int PID, int addr) +{ + if (addr >= pageSize) + { + std::cout << "failure" << std::endl; + return; + } + + Process *p = ht->Get(PID); + // if we do not have any memory allocated to PID + if (p == nullptr) + { + std::cout << "failure" << std::endl; + return; + } + + std::cout << addr << " " << memory[p->getStartingIndex() * pageSize + addr] << std::endl; +} + +/// @brief Deallocate memory from process PID. +/// @param PID The PID of the process to dealocate memory from +/// @return true if successful, false otherwise +bool VirtualMemory::Delete(unsigned int PID) +{ + Process *p = ht->Get(PID); + + if (p == nullptr) + return false; + + freeMemory.push_back(p->getStartingIndex()); + + return ht->Remove(PID); +} + +/// @brief Print the chain of the hash table at index m +/// @param m the index of the chain to print +void VirtualMemory::Print(int m) +{ + ht->Print(m); +} diff --git a/P2/VirtualMemory.h b/P2/VirtualMemory.h new file mode 100644 index 0000000..ec20f68 --- /dev/null +++ b/P2/VirtualMemory.h @@ -0,0 +1,30 @@ +#ifndef VIRTUALMEMORY_H +#define VIRTUALMEMORY_H + +#include "Process.h" +#include "HashTable.h" + +class VirtualMemory +{ +public: + VirtualMemory(int n, int p, bool chaining); + ~VirtualMemory(); + + bool Insert(unsigned int PID); + int Search(unsigned int PID); + + bool Write(unsigned int PID, int addr, int x); + void Read(unsigned int PID, int addr); + + bool Delete(unsigned int PID); + void Print(int m); + +private: + HashTable *ht; + int memorySize; + int pageSize; + int *memory; + std::vector freeMemory; + bool chaining; +}; +#endif diff --git a/P2/test.cpp b/P2/test.cpp new file mode 100644 index 0000000..5493d49 --- /dev/null +++ b/P2/test.cpp @@ -0,0 +1,103 @@ +#include + +#include "VirtualMemory.h" + +using namespace std; + +int main() +{ + string cmd; + VirtualMemory *vm = nullptr; + bool chaining = true; + + while (cin >> cmd) + { + if (cmd == "OPEN") + { + chaining = false; + } + else if (cmd == "ORDERED") + { + chaining = true; + } + if (cmd == "M") + { + int N; + int P; + cin >> N; + cin >> P; + + vm = new VirtualMemory(N, P, chaining); + + cout << "success" << endl; + } + else if (cmd == "INSERT") + { + unsigned int PID; + cin >> PID; + + if (vm->Insert(PID)) + cout << "success" << endl; + else + cout << "failure" << endl; + } + else if (cmd == "SEARCH") + { + unsigned int PID; + cin >> PID; + + int ret = vm->Search(PID); + if (ret == -1) + cout << "not found" << endl; + else + cout << "found " << PID << " in " << ret << endl; + } + else if (cmd == "WRITE") + { + unsigned int PID; + int ADDR; + int x; + + cin >> PID; + cin >> ADDR; + cin >> x; + + if (vm->Write(PID, ADDR, x)) + cout << "success" << endl; + else + cout << "failure" << endl; + } + else if (cmd == "READ") + { + unsigned int PID; + int ADDR; + + cin >> PID; + cin >> ADDR; + + vm->Read(PID, ADDR); + } + else if (cmd == "DELETE") + { + unsigned int PID; + cin >> PID; + + if (vm->Delete(PID)) + cout << "success" << endl; + else + cout << "failure" << endl; + } + else if (cmd == "PRINT") + { + int m; + cin >> m; + + vm->Print(m); + } + else if (cmd == "END") + { + break; + } + } + delete vm; +} diff --git a/P3/Makefile b/P3/Makefile new file mode 100644 index 0000000..04bdd81 --- /dev/null +++ b/P3/Makefile @@ -0,0 +1,2 @@ +all: trietest.cpp Trie.cpp + g++ -std=c++11 trietest.cpp Trie.cpp \ No newline at end of file diff --git a/P3/Trie.cpp b/P3/Trie.cpp new file mode 100644 index 0000000..aaba389 --- /dev/null +++ b/P3/Trie.cpp @@ -0,0 +1,218 @@ +#include "Trie.h" +#include "illegal_exception.h" + +Trie::Trie() +{ + children = new Trie *[MAX_SLOTS]; + isEnd = false; + for (int i = 0; i < MAX_SLOTS; i++) + { + children[i] = nullptr; + } + count = 0; +} + +Trie::~Trie() +{ + delete[] children; +} + +/// @brief Wrapper function to recursively insert string s into the trie. +/// @param s The string to insert into the trie. +/// @return True if the string was inserted, false otherwise. +bool Trie::Insert(std::string s) +{ + // Wrapper function is needed to meet illegal_exception criteria without having O(n^2) runtime (recursive function). + for (int i = 0; i < s.length(); i++) + { + if (s[i] < ASCII_FACTOR || s[i] > ASCII_UPPER) + { + throw illegal_exception(); + } + } + return PerformInsert(s); +} + +/// @brief Recursive function to insert string s into the trie. +/// @param s The string to insert into the trie. +/// @return True if the string was inserted successfully, false otherwise. +bool Trie::PerformInsert(std::string s) +{ + if (s.length() > 0) // Add until there are no more characters. + { + char c = s.at(0); + // Create the new trie if it does not exist. This condition will never be true if the word cannot be inserted. + if (children[c - ASCII_FACTOR] == nullptr) + children[c - ASCII_FACTOR] = new Trie(); + + // Recursively insert, checking if the previous insertion was successful (if so, increment count). + if (children[c - ASCII_FACTOR]->PerformInsert(s.substr(1))) + { + count++; + return true; + } + } + // If there are no characters and we have not reached a word end then the word is not already added. + else if (!this->isEnd) + { + this->isEnd = true; + count++; + return true; + } + return false; // If the word is already in the trie, return false. +} + +/// @brief Wrapper function to remove an element from the trie. +/// @param s The string to remove from the trie. +/// @return True if the element was removed successfully, false otherwise. +bool Trie::Remove(std::string s) +{ + // Achieve O(n) runtime using wrapper function. + for (int i = 0; i < s.length(); i++) + { + if (s[i] < ASCII_FACTOR || s[i] > ASCII_UPPER) + { + throw illegal_exception(); + } + } + return PerformRemove(s); +} + +/// @brief Recursively remove string s from the trie. +/// @param s The string to remove from the trie. +/// @return True if the string was removed, false otherwise. +bool Trie::PerformRemove(std::string s) +{ + if (s.length() > 0) // Remove until there are no more characters to remove. + { + // If we have reached a trie that does not have the correct child, we cannot remove the word. + char c = s.at(0); + if (children[c - ASCII_FACTOR] == nullptr) + return false; + + // Recursively remove the remaining bit of the word. Subtracting from the count if successful. + if (children[c - ASCII_FACTOR]->PerformRemove(s.substr(1))) + { + count--; + + // Free any child tries that have a count of 0. These are guaranteed to have no children. + for (int i = 0; i < MAX_SLOTS; i++) + { + if (children[i] != nullptr && children[i]->IsEmpty()) + { + delete children[i]; + children[i] = nullptr; + } + } + + return true; // If previous removes were successful, this remove is also successful. + } + } + // If we have reached the end of the word, we can succesfully remove it from the trie. + else if (this->isEnd) + { + this->isEnd = false; + count--; + return true; + } + + return false; // When we are out of characters, but did not find a word end, cannot remove. +} + +/// @brief Determine if the trie is empty. +/// @return True if the trie is empty, false otherwise. +bool Trie::IsEmpty() +{ + return count == 0; +} + +/// @brief Empty the trie. +void Trie::Clear() +{ + // We do not need to worry about dangling pointers, since everything is being deleted in order. + for (int i = 0; i < MAX_SLOTS; i++) + { + if (children[i] != nullptr) + children[i]->Clear(); // Recursively delete any non-null pointer children. + } + + delete this; +} + +/// @brief Perform a depth first search on the trie for string s, outputting the result by performing in place modification of the vector out. +/// @param out +/// @param s +void Trie::DepthFirstSearch(std::vector *out, std::string s) +{ + if (isEnd) + out->push_back(s); // If we have reached the end, put the word into the output + + // Recursively search children nodes, in order from A-Z. + for (int i = 0; i < MAX_SLOTS; i++) + { + if (children[i] != nullptr) + children[i]->DepthFirstSearch(out, s + (char)(i + ASCII_FACTOR)); + } +} + +/// @brief Get the number of words in the trie. +/// @return An integer of the number of words in the trie. +int Trie::Size() +{ + return count; +} + +/// @brief Wrapper function to count the number of suffixes for a given string s. +/// @param s +/// @return +int Trie::CountSuffixes(std::string s) +{ + for (int i = 0; i < s.length(); i++) + { + if (s[i] < ASCII_FACTOR || s[i] > ASCII_UPPER) + { + throw illegal_exception(); + } + } + return PerformCountSuffixes(s); +} + + +int Trie::PerformCountSuffixes(std::string s) +{ + if (s.empty()) + return count; + + char c = s.at(0); + int index = c - ASCII_FACTOR; + + if (children[index] != nullptr) + return children[index]->PerformCountSuffixes(s.substr(1)); + else + return 0; +} + +bool Trie::SpellCheck(std::vector *out, std::string check, std::string s) +{ + if (check.empty() && isEnd) + return true; + else if (check.empty()) + return false; + + char c = check.at(0); + int index = c - ASCII_FACTOR; +; + if (children[index] != nullptr) + { + if (children[index]->SpellCheck(out, check.substr(1), s + c)) + { + return true; + } + else + { + children[index]->DepthFirstSearch(out, s + c); + return true; + } + } + return false; +} diff --git a/P3/Trie.h b/P3/Trie.h new file mode 100644 index 0000000..6cd5ec6 --- /dev/null +++ b/P3/Trie.h @@ -0,0 +1,33 @@ +#ifndef TRIE_H +#define TRIE_H + +#include +#include + +class Trie +{ +public: + Trie(); + ~Trie(); + bool Insert(std::string s); + bool Remove(std::string s); + void DepthFirstSearch(std::vector *out, std::string s); + bool IsEmpty(); + void Clear(); + int Size(); + int CountSuffixes(std::string s); + bool SpellCheck(std::vector *out, std::string check, std::string s); + +private: + const int MAX_SLOTS = 26; + const int ASCII_FACTOR = 65; + const int ASCII_UPPER = 90; + int count; + bool isEnd; + Trie **children; + + bool PerformInsert(std::string s); + bool PerformRemove(std::string s); + int PerformCountSuffixes(std::string s); +}; +#endif \ No newline at end of file diff --git a/P3/illegal_exception.h b/P3/illegal_exception.h new file mode 100644 index 0000000..bf45886 --- /dev/null +++ b/P3/illegal_exception.h @@ -0,0 +1,8 @@ +#ifndef ILLEGAL_EXCEPTION_H +#define ILLEGAL_EXCEPTION_H + +#include + +class illegal_exception : std::exception {}; + +#endif diff --git a/P3/trietest.cpp b/P3/trietest.cpp new file mode 100644 index 0000000..b502584 --- /dev/null +++ b/P3/trietest.cpp @@ -0,0 +1,153 @@ +#include +#include +#include "Trie.h" +#include +#include "illegal_exception.h" + +using namespace std; + +const string FILE_NAME = "corpus.txt"; + +void PrintVector(vector *out) +{ + for (int i = 0; i < out->size(); i++) + { + cout << (*out)[i]; + if (i < out->size() - 1) + cout << " "; + } +} + +int main() +{ + string cmd; + string addWord; + ifstream fin(FILE_NAME); + Trie *trie = new Trie(); + + while (cin >> cmd) + { + if (cmd == "load") + { + if (!fin.is_open()) + fin.open(FILE_NAME); + + while (fin >> addWord) + { + trie->Insert(addWord); + } + + fin.close(); + cout << "success" << endl; + } + else if (cmd == "i") + { + string word; + cin >> word; + try + { + if (trie->Insert(word)) + cout << "success" << endl; + else + cout << "failure" << endl; + } + catch (illegal_exception e) + { + cout << "illegal argument" << endl; + } + } + else if (cmd == "e") + { + string word; + cin >> word; + + try + { + if (trie->Remove(word)) + cout << "success" << endl; + else + cout << "failure" << endl; + } + catch (illegal_exception e) + { + cout << "illegal argument" << endl; + } + } + else if (cmd == "clear") + { + trie->Clear(); + trie = new Trie(); + cout << "success" << endl; + } + else if (cmd == "size") + { + cout << "number of words is " << trie->Size() << endl; + } + else if (cmd == "empty") + { + if (trie->IsEmpty()) + cout << "empty 1" << endl; + else + cout << "empty 0" << endl; + } + else if (cmd == "spellcheck") + { + string word; + cin >> word; + + vector out; + + bool result = trie->SpellCheck(&out, word, ""); + + if (out.empty() && result) + { + cout << "correct" << endl; + } + else if (!result) + { + cout << endl; + } + else + { + PrintVector(&out); + cout << endl; + } + } + else if (cmd == "p") + { + vector out; + trie->DepthFirstSearch(&out, ""); + + PrintVector(&out); + + if (out.size() > 0) + cout << endl; + + } + + else if (cmd == "c") + { + string prefix; + cin >> prefix; + + try + { + int count = trie->CountSuffixes(prefix); + + if (count != -1 && count != 0) + cout << "count is " << count << endl; + else + cout << "not found" << endl; + } + catch (illegal_exception e) + { + cout << "illegal argument" << endl; + } + } + else if (cmd == "exit") + { + break; + } + } + trie->Clear(); +} diff --git a/P4/Graph.cpp b/P4/Graph.cpp new file mode 100644 index 0000000..42f1366 --- /dev/null +++ b/P4/Graph.cpp @@ -0,0 +1,189 @@ +#include "Graph.h" +#include +#include "PriorityQueue.h" +#include "illegal_exception.h" + +/// @brief Create a new graph +/// @param maxCount The maximum number of elements the graph is required to store +/// @param mst A flag to enable MST (enabling makes the runtime of the graph worse) +Graph::Graph(int maxCount, bool mst) +{ + vertexList.reserve(maxCount); + if (!mst) + pq = new PriorityQueue(maxCount); + this->maxCount = maxCount; + this->mstEnabled = mst; +} + +Graph::~Graph() +{ + delete pq; +} + +/// @brief Insert an edge from vertex a to b, with weight w. When MST flag is true, it is invalid to pass in edges that already exist in the graph. +/// @param a Vertex a +/// @param b Vertex b +/// @param weight The weight of the edge to insert +/// @return True if successful, false otherwise +/// @throws illegal_exception if given invalid input +bool Graph::Insert(int a, int b, int weight) +{ + // Check input validity + if (a > 50000 || a < 1 || b > 50000 || b < 1 || weight < 1) + { + throw illegal_exception(); + } + + // Check if the node already exists. Skip this check when the MST is disabled - allows efficient inserts for building tree. + int count = adjacencyList[a].size(); + if (!mstEnabled) + { + + for (int i = 0; i < count; i++) + { + int currentData = std::get<0>(adjacencyList[a][i]); + if (currentData == b) + return false; + } + } + + // Add the b vertex to the adjacency list for a + adjacencyList[a].push_back(std::make_tuple(b, weight)); + + // Add the vertex a to the vertexList, if a has never been added to the graph + if (count == 0) + vertexList.insert(vertexList.begin() + vertexList.size(), std::make_tuple(a, INT_MAX, -1)); + + // Add a vertex to the adjacency list for b, and insert b into vertexList if required + count = adjacencyList[b].size(); + adjacencyList[b].push_back(std::make_tuple(a, weight)); + if (count == 0) + vertexList.insert(vertexList.begin() + vertexList.size(), std::make_tuple(b, INT_MAX, -1)); + + return true; +} + +/// @brief Delete vertex a from the graph. +/// @param a The vertex to delete from the graph. +/// @return True if successful, false otherwise. +/// @throws illegal_exception if given invalid input. +bool Graph::Delete(int a) +{ + // Check input conditions + if (a > 50000 || a < 1) + { + throw illegal_exception(); + } + + // Ensure the vertex is in the graph + int count = adjacencyList[a].size(); + if (count == 0) + return false; + + // Remove all references to the vertex in the adjacency lists of other vertices, and in the vertexList. + while (count != 0) + { + std::tuple lastData = adjacencyList[a][count - 1]; + adjacencyList[a].pop_back(); + + // Remove vertex from all adjacency lists + for (int j = 0; j < adjacencyList[std::get<0>(lastData)].size(); j++) + { + if (std::get<0>(adjacencyList[std::get<0>(lastData)][j]) == a) + { + adjacencyList[std::get<0>(lastData)].erase(adjacencyList[std::get<0>(lastData)].begin() + j); + } + } + + // If removing vertex a causes any adjacency lists to become empty, remove that vertex from the vertexList. + if (adjacencyList[std::get<0>(lastData)].size() < 1) + { + for (int j = 0; j < vertexList.size(); j++) + { + if (std::get<0>(vertexList[j]) == std::get<0>(lastData)) + vertexList.erase(vertexList.begin() + j); + } + } + + count--; + } + + // Remove a from the vertex list. + for (int i = 0; i < vertexList.size(); i++) + { + if (std::get<0>(vertexList[i]) == a) + vertexList.erase(vertexList.begin() + i); + } + + return true; +} + +/// @brief Get a vector containing the adjacent vertices to a +/// @param a The vertex to check +/// @return A vector of all vertices +/// @throws illegal_exception if given invalid input. +std::vector> *Graph::GetAdjacent(int a) +{ + if (a > 50000 || a < 1) + { + throw illegal_exception(); + } + + return &adjacencyList[a]; +} + +/// @brief Compute the MST of the graph +/// @param out A vector to output the resulting MST edges in +/// @return The cost of the MST +int Graph::MST(std::vector> *out) +{ + // If there are no nodes, or somehow only one node. + if (vertexList.size() < 2) + return 0; + + // When there is only one edge, that edge is the MST + if (vertexList.size() < 3) + { + out->push_back(std::make_tuple(std::get<0>(vertexList[0]), std::get<0>(vertexList[1]), std::get<1>(adjacencyList[std::get<0>(vertexList[0])][0]))); + return std::get<1>(adjacencyList[std::get<0>(vertexList[0])][0]); + } + + // Attribution: Some of the Pseudocode used to write this function is from the CLRS textbook. + int cost = 0; + pq->Init(&vertexList); + + // Apply Prim's Algorithm using a PriorityQueue. + // Extract elements from the PQ until it is empty + while (!pq->IsEmpty()) + { + // Extract the element with the lowest weight + std::tuple u = pq->HeapExtractMin(); + + // Prevent insertion of first node (or any infinite weights). + if (std::get<1>(u) != INT_MAX) + { + out->push_back(std::make_tuple(std::get<2>(u), std::get<0>(u), std::get<1>(u))); + cost += std::get<1>(u); + } + + // Iterate through all of the adjacent vertices + for (int i = 0; i < adjacencyList[std::get<0>(u)].size(); i++) + { + std::tuple v = adjacencyList[std::get<0>(u)][i]; // The vertex being examined + + // If the current path is better than the stored path, update it. + if (pq->Contains(std::get<0>(v)) && std::get<1>(v) < pq->GetKey(std::get<0>(v))) + { + pq->Modify(std::get<0>(v), std::get<1>(v), std::get<0>(u)); + } + } + } + return cost; +} + +/// @brief Get the number of vertices in the graph +/// @return The number of vertices in the graph +int Graph::GetVertexCount() +{ + return vertexList.size(); +} diff --git a/P4/Graph.h b/P4/Graph.h new file mode 100644 index 0000000..fef3866 --- /dev/null +++ b/P4/Graph.h @@ -0,0 +1,27 @@ +#ifndef TRIE_H +#define TRIE_H + +#include +#include +#include +#include "PriorityQueue.h" + +class Graph +{ +public: + Graph(int maxCount, bool mst); + ~Graph(); + bool Insert(int a, int b, int weight); + bool Delete(int a); + std::vector> *GetAdjacent(int a); + int GetVertexCount(); + int MST(std::vector> *outList); + +private: + PriorityQueue *pq; + std::vector> adjacencyList[50001]; // An array of vectors of tuples + std::vector> vertexList; // List of all vertices in the graph stored as + int maxCount; + bool mstEnabled; +}; +#endif diff --git a/P4/Makefile b/P4/Makefile new file mode 100644 index 0000000..76ab158 --- /dev/null +++ b/P4/Makefile @@ -0,0 +1,2 @@ +all: Test.cpp Graph.cpp PriorityQueue.cpp + g++ -std=c++11 Test.cpp Graph.cpp PriorityQueue.cpp diff --git a/P4/PriorityQueue.cpp b/P4/PriorityQueue.cpp new file mode 100644 index 0000000..aaa7dab --- /dev/null +++ b/P4/PriorityQueue.cpp @@ -0,0 +1,153 @@ +#include "PriorityQueue.h" +#include + +// Attribution: Some of the Pseudocode used to write these functions is from the CLRS textbook. + +PriorityQueue::PriorityQueue(int maxCount) +{ + count = 0; + locations.reserve(maxCount); + arr.reserve(maxCount); + for (int i = 0; i < maxCount; i++) + { + locations[i] = -1; + } +} + +/// @brief Initialize the priority queue with the given vector of tuples. The tuples should be in the format: +/// @param vertexList The vector of tuples to insert into the priority queue. +void PriorityQueue::Init(std::vector> *vertexList) +{ + count = vertexList->size(); + + for (int i = 0; i < count; i++) + { + arr[i] = vertexList->at(i); + locations[std::get<0>(vertexList->at(i))] = i; + } +} + +/// @brief Modify the weight and/or the parent of vertex v +/// @param v The vertex to modify (not the index in the priority queue) +/// @param w The weight to set +/// @param parent The parent to set +/// @return True if successful, false otherwise +bool PriorityQueue::Modify(int v, int w, int parent) +{ + if (count < 1) + return false; + + int i = locations[v]; + if (i < 0) + return false; + + std::get<1>(arr[i]) = w; + std::get<2>(arr[i]) = parent; + while (i > 0 && std::get<1>(arr[Parent(i)]) > std::get<1>(arr[i])) + { + + Exchange(i, Parent(i)); + i = Parent(i); + } + return true; +} + +/// @brief Extract the smallest value from the priority queue (the topmost element, since this is a min pq). +/// @return The element in the priority queue if not empty, or a tuple of all ints <-1, -1, -1> if empty +std::tuple PriorityQueue::HeapExtractMin() +{ + // Signal no minimum element if there are no elements. + if (IsEmpty()) + return std::make_tuple(-1, -1, -1); + + std::tuple min = arr[0]; + + locations[std::get<0>(arr[count - 1])] = 0; + locations[std::get<0>(min)] = -1; + arr[0] = arr[count - 1]; + count--; + MinHeapify(0); + return min; +} + +/// @brief Run the MinHeapify algorithm on the pq. +/// @param i The index (not the vertex). +void PriorityQueue::MinHeapify(int i) +{ + int l = Left(i); + int r = Right(i); + + int smallest = i; + + if (l < count && std::get<1>(arr[l]) < std::get<1>(arr[i])) + smallest = l; + + if (r < count && std::get<1>(arr[r]) < std::get<1>(arr[smallest])) + smallest = r; + + if (smallest != i) + { + Exchange(i, smallest); + MinHeapify(smallest); + } +} + +/// @brief Get a boolean value to determine if the priority queue is empty +/// @return True if the priority queue is empty, false otherwise. +bool PriorityQueue::IsEmpty() +{ + return count < 1; +} + +/// @brief Check if the priority queue contains a vertex v. +/// @param v The vertex (not index) to check. +/// @return True if the vertex (not index) is contained in the priority queue, false otherwise. +bool PriorityQueue::Contains(int v) +{ + return locations[v] != -1; +} + +/// @brief Get the key (weight) of a vertex (not index) in the priority queue +/// @param v The vertex (not index) to get the weight for +/// @return The key (weight) of the vertex +int PriorityQueue::GetKey(int v) +{ + return std::get<1>(arr[locations[v]]); +} + +/// @brief Swap the elements of index a and index b (not the vertex number) +/// @param a The index (not vertex) of the element to swap +/// @param b The index (not vertex) of the element to swap +void PriorityQueue::Exchange(int a, int b) +{ + locations[std::get<0>(arr[a])] = b; + locations[std::get<0>(arr[b])] = a; + + std::tuple temp = arr[a]; + arr[a] = arr[b]; + arr[b] = temp; +} + +/// @brief Given an index (not vertex), get the parent of that index (not vertex) +/// @param i The index (not vertex) to get the parent of +/// @return The index (not vertex) of the parent +int PriorityQueue::Parent(int i) +{ + return (i - 1) / 2; +} + +/// @brief Given an index (not vertex), get the left child of that index (not vertex) +/// @param i The index (not vertex) to get the left child of +/// @return The index (not vertex) of the left child +int PriorityQueue::Left(int i) +{ + return 2 * i + 1; +} + +/// @brief Given an index (not vertex), get the right child of that index (not vertex) +/// @param i The index (not vertex) to get the right child of +/// @return The index (not vertex) of the right child +int PriorityQueue::Right(int i) +{ + return 2 * i + 2; +} diff --git a/P4/PriorityQueue.h b/P4/PriorityQueue.h new file mode 100644 index 0000000..ce4d17d --- /dev/null +++ b/P4/PriorityQueue.h @@ -0,0 +1,31 @@ +#ifndef PRIORITYQUEUE_H +#define PRIORITYQUEUE_H + +#include +#include +#include + +class PriorityQueue +{ +public: + PriorityQueue(int maxCount); + void Init(std::vector> *vertexList); + std::tuple HeapExtractMin(); + bool Modify(int i, int w, int parent); + bool Contains(int v); + bool IsEmpty(); + int GetKey(int v); + +private: + int count; + void Exchange(int a, int b); + void MinHeapify(int i); + int Parent(int i); + int Left(int i); + int Right(int i); + std::vector> arr; // The actual priority queue. + std::vector locations; // References for vertex -> PQ index. Allows indexing PQ in O(1) time. + const int MAX_UNIQUE_KEYS = 50001; +}; + +#endif diff --git a/P4/Test.cpp b/P4/Test.cpp new file mode 100644 index 0000000..e8be2d5 --- /dev/null +++ b/P4/Test.cpp @@ -0,0 +1,180 @@ +#include +#include +#include "Graph.h" +#include "illegal_exception.h" + +using namespace std; + +const int MAX_NODE_COUNT = 50001; + +int main() +{ + string cmd; + Graph *graph = new Graph(MAX_NODE_COUNT, false); + bool mstModified = true; + int prevCost = 0; + std::vector> prevOutput; + + while (cin >> cmd) + { + if (cmd == "LOAD") + { + mstModified = true; + string filename; + cin >> filename; + + ifstream fin(filename.c_str()); + + int count; + fin >> count; + + int n1; + while (fin >> n1) + { + int n2; + fin >> n2; + int w; + fin >> w; + + graph->Insert(n1, n2, w); + } + + fin.close(); + cout << "success" << endl; + } + else if (cmd == "INSERT") + { + int a; + int b; + int w; + + cin >> a; + cin >> b; + cin >> w; + + try + { + if (graph->Insert(a, b, w)) + { + mstModified = true; + std::cout << "success" << std::endl; + } + + else + { + std::cout << "failure" << std::endl; + } + } + catch (illegal_exception) + { + std::cout << "illegal argument" << std::endl; + } + } + else if (cmd == "DELETE") + { + int a; + cin >> a; + + try + { + if (graph->Delete(a)) + { + mstModified = true; + std::cout << "success" << std::endl; + } + else + { + std::cout << "failure" << std::endl; + } + } + catch (illegal_exception) + { + std::cout << "illegal argument" << std::endl; + } + } + else if (cmd == "PRINT") + { + int a; + cin >> a; + + try + { + std::vector> *out = graph->GetAdjacent(a); + for (int i = 0; i < out->size(); i++) + { + std::cout << get<0>(out->at(i)) << " "; + } + + if (out->size() < 1) + { + std::cout << "failure"; + } + std::cout << endl; + } + catch (illegal_exception) + { + std::cout << "illegal argument" << std::endl; + } + } + else if (cmd == "MST") + { + // Prevent useless regeneration of MST. + if (!mstModified) + { + if (prevOutput.size() < 1) + std::cout << "failure"; + + for (int i = 0; i < prevOutput.size(); i++) + { + std::cout << std::get<0>(prevOutput[i]) << " " << std::get<1>(prevOutput[i]) << " " << std::get<2>(prevOutput[i]) << " "; + } + + std::cout << std::endl; + } + else + { + std::vector> out; + out.reserve(graph->GetVertexCount()); + prevCost = graph->MST(&out); + prevOutput = out; + + for (int i = 0; i < out.size(); i++) + { + std::cout << std::get<0>(out[i]) << " " << std::get<1>(out[i]) << " " << std::get<2>(out[i]) << " "; + } + + if (out.size() < 1) + std::cout << "failure"; + + std::cout << std::endl; + mstModified = false; + } + } + else if (cmd == "COST") + { + // Prevent useless regeneration of MST. + if (!mstModified) + { + std::cout << "cost is " << prevCost << std::endl; + } + else + { + std::vector> out; + out.reserve(graph->GetVertexCount()); + int cost = graph->MST(&out); + prevOutput = out; + prevCost = cost; + + std::cout << "cost is " << cost << std::endl; + mstModified = false; + } + } + + else if (cmd == "END") + { + break; + } + } + + delete graph; +} diff --git a/P4/illegal_exception.h b/P4/illegal_exception.h new file mode 100644 index 0000000..fe379b6 --- /dev/null +++ b/P4/illegal_exception.h @@ -0,0 +1,10 @@ +#ifndef ILLEGAL_EXCEPTION_H +#define ILLEGAL_EXCEPTION_H + +#include + +class illegal_exception : std::exception +{ +}; + +#endif