diff --git a/Uebung 4/Uebung4_2/hashTable.cpp b/Uebung 4/Uebung4_2/hashTable.cpp index 98294ee..757282b 100644 --- a/Uebung 4/Uebung4_2/hashTable.cpp +++ b/Uebung 4/Uebung4_2/hashTable.cpp @@ -2,134 +2,180 @@ #include HashTable::HashTable() { - this->size = 0; - this->entries = nullptr; - this->setHashFunction("lastNumber"); + this->size = 0; + this->entries = nullptr; + this->setHashFunction("mod17"); + this->numberOfEntries = 0; } -HashTable::HashFunction::HashFunction(std::string name, hashFunctionPtr algorithm, int size) { - this->name = name; - this->algorithm = algorithm; - this->size = size; +HashTable::HashFunction::HashFunction(std::string name, + hashFunctionPtr algorithm, int size) { + this->name = name; + this->algorithm = algorithm; + this->size = size; } +void HashTable::insert(PbEntry *entry) { + int hashValue = this->hashFunction(entry->telephoneNumber); + hashValue = hashValue % this->size; -void HashTable::insert(PbEntry* entry) { - int hashValue = this->hashFunction(entry->telephoneNumber); - hashValue = hashValue % this->size; - - if(this->entries[hashValue].key == "" || this->entries[hashValue].key == "deleted") { - this->entries[hashValue].key = entry->telephoneNumber; - this->entries[hashValue].phonebookEntry = entry; - } else { - bool inserted = false; - int i = (hashValue + 1) % this->size; - while(inserted == false) { - if(i == hashValue) { - std::cout << "HashTable full!" << std::endl; - return; - } - if(this->entries[i].key == "" || this->entries[i].key == "deleted") { - this->entries[i].key = entry->telephoneNumber; - this->entries[i].phonebookEntry = entry; - inserted = true; - } - i = (i + 1) % this->size; - } + if (this->entries[hashValue].key == "" || + this->entries[hashValue].key == "deleted") { + this->entries[hashValue].key = entry->telephoneNumber; + this->entries[hashValue].phonebookEntry = entry; + this->numberOfEntries++; + } else { + bool inserted = false; + int i = (hashValue + 1) % this->size; + while (inserted == false) { + if (i == hashValue) { + std::cout << "HashTable full!" << std::endl; + return; + } + if (this->entries[i].key == "" || this->entries[i].key == "deleted") { + this->entries[i].key = entry->telephoneNumber; + this->entries[i].phonebookEntry = entry; + this->numberOfEntries++; + inserted = true; + } + i = (i + 1) % this->size; } + } + std::cout << "Number of current Entries: " << this->numberOfEntries + << ", LoadFactor: " << this->getloadFactor() << std::endl; + if (this->getloadFactor() > 2.0 / 3.0) { + if (this->size <= 17) { + std::cout << "Upgrading to mod37" << std::endl; + this->setHashFunction("mod37"); + } else if (this->size <= 37) { + std::cout << "Upgrading to mod71!" << std::endl; + this->setHashFunction("mod71"); + } else { + std::cout << "Cannot upgrade further. Desastrous Failure imminent!!" + << std::endl; + if (this->numberOfEntries == this->size) { + std::cout + << "Could not insert. Hashtable is full and can not be expanded" + << std::endl; + return; + } + } + } } void HashTable::print() { - std::cout << "=====================================" << std::endl; - for(int i = 0; i < this->size; i++) { - std::cout << i << " :\t" << this->entries[i].key << std::endl; - - } - std::cout << "=====================================" << std::endl; + std::cout << "=====================================" << std::endl; + for (int i = 0; i < this->size; i++) { + std::cout << i << " :\t" << this->entries[i].key << std::endl; + } + std::cout << "=====================================" << std::endl; } void HashTable::setHashFunction(std::string algorithmName) { - for(int i = 0; i < 4; i++) { - if(this->availableAlgorithms[i].name == algorithmName) { - this->hashFunction = this->availableAlgorithms[i].algorithm; - this->size = this->availableAlgorithms[i].size; - if(this->entries != nullptr) { - delete[] this->entries; - } - this->entries = new HashNode[this->size]; - return; - } - } + for (int i = 0; i < 6; i++) { + if (this->availableAlgorithms[i].name == algorithmName) { + HashNode *oldEntries = this->entries; + int oldsize = this->size; + this->hashFunction = this->availableAlgorithms[i].algorithm; + this->size = this->availableAlgorithms[i].size; + this->numberOfEntries = 0; + this->entries = new HashNode[this->size]; + if (oldEntries != nullptr) { + for (int i = 0; i < oldsize; i++) { + if (oldEntries[i].phonebookEntry != nullptr) { - std::cerr << "The Hash Function provided was not found!" << std::endl; + this->insert(oldEntries[i].phonebookEntry); + } + } + delete[] oldEntries; + } + return; + } + } + + std::cerr << "The Hash Function provided was not found!" << std::endl; } -const PbEntry* HashTable::search(std::string key) { - int hashValue = this->hashFunction(key); // key is "hashed" and stored in the variable int hashValue - hashValue = hashValue % this->size; - int i = 0; - while(this->entries[hashValue].key != key && this->entries[hashValue].key != "" && i <= this->size) { - hashValue = (hashValue + 1) % this->size; - i++; - } +const PbEntry *HashTable::search(std::string key) { + int hashValue = this->hashFunction( + key); // key is "hashed" and stored in the variable int hashValue + hashValue = hashValue % this->size; + int i = 0; + while (this->entries[hashValue].key != key && + this->entries[hashValue].key != "" && i <= this->size) { + hashValue = (hashValue + 1) % this->size; + i++; + } - if(this->entries[hashValue].key == key) { - return this->entries[hashValue].phonebookEntry; - } else { - std::cout << "Entry with telephone number " << key << " not found!" << std::endl; - return nullptr; - } + if (this->entries[hashValue].key == key) { + return this->entries[hashValue].phonebookEntry; + } else { + std::cout << "Entry with telephone number " << key << " not found!" + << std::endl; + return nullptr; + } } bool HashTable::deleteItem(std::string key) { - int hashValue = this->hashFunction(key); - hashValue = hashValue % this->size; + int hashValue = this->hashFunction(key); + hashValue = hashValue % this->size; - while(this->entries[hashValue].key != key && this->entries[hashValue].key != "") { - hashValue = (hashValue + 1) % this->size; - } + while (this->entries[hashValue].key != key && + this->entries[hashValue].key != "") { + hashValue = (hashValue + 1) % this->size; + } - if(this->entries[hashValue].key == key) { - this->entries[hashValue].key = "deleted"; - this->entries[hashValue].phonebookEntry = nullptr; - delete this->entries[hashValue].phonebookEntry; - return true; - } else { - return false; - } + if (this->entries[hashValue].key == key) { + this->entries[hashValue].key = "deleted"; + this->entries[hashValue].phonebookEntry = nullptr; + delete this->entries[hashValue].phonebookEntry; + this->numberOfEntries--; + + return true; + } else { + return false; + } } - +float HashTable::getloadFactor() { + return (float)this->numberOfEntries / this->size; +} /* algorithm that "hashes" the last digit of a number */ int lastNumber(std::string telNr) { - if(telNr.length() <=0) { - std::cerr << "Number '" << telNr << "' does not contain enough digits. At least 1 needed!"; - exit(1); - } - return std::stoi(std::string(telNr.end()-1, telNr.end())); + if (telNr.length() <= 0) { + std::cerr << "Number '" << telNr + << "' does not contain enough digits. At least 1 needed!"; + exit(1); + } + return std::stoi(std::string(telNr.end() - 1, telNr.end())); } /* algorithm that "hashes" the first three digits of a number */ int firstThreeNumbers(std::string telNr) { - if(telNr.length() < 3) { - std::cerr << "Number '" << telNr << "' does not contain enough digits. At least 3 needed!"; - exit(1); - } - return std::stoi(std::string(telNr.begin(), telNr.begin()+3)); + if (telNr.length() < 3) { + std::cerr << "Number '" << telNr + << "' does not contain enough digits. At least 3 needed!"; + exit(1); + } + return std::stoi(std::string(telNr.begin(), telNr.begin() + 3)); } /* algorithm that "hashes" the last three digits of a number */ int lastThreeNumbers(std::string telNr) { - if(telNr.length() < 3) { - std::cerr << "Number '" << telNr << "' does not contain enough digits. At least 3 needed!"; - exit(1); - } - return std::stoi(std::string(telNr.end()-3, telNr.end())); + if (telNr.length() < 3) { + std::cerr << "Number '" << telNr + << "' does not contain enough digits. At least 3 needed!"; + exit(1); + } + return std::stoi(std::string(telNr.end() - 3, telNr.end())); } /* algorithm that "hashes" the through mod17 */ -int mod17(std::string telNr) { - return (int)(std::stol(telNr)%17); -} +int mod17(std::string telNr) { return (int)(std::stol(telNr) % 17); } +/* algorithm that "hashes" the through mod37 */ +int mod37(std::string telNr) { return (int)(std::stol(telNr) % 37); } + +/* algorithm that "hashes" the through mod71 */ +int mod71(std::string telNr) { return (int)(std::stol(telNr) % 71); } diff --git a/Uebung 4/Uebung4_2/hashTable.h b/Uebung 4/Uebung4_2/hashTable.h index 1d043b0..4316091 100644 --- a/Uebung 4/Uebung4_2/hashTable.h +++ b/Uebung 4/Uebung4_2/hashTable.h @@ -1,44 +1,65 @@ -#include #include "pbEntry.h" +#include #pragma once -typedef int (*hashFunctionPtr)(std::string); // typedefinition of a pointer for a hashfunction; they all need conform to the guideline: int (std::string ) -int lastNumber(std::string telNr); // hash algorithm that uses only the last digit of a given telNr -int firstThreeNumbers(std::string telNr); // hash algorithm that uses the first three digits of a given telNr -int lastThreeNumbers(std::string telNr); // hash algorithm that uses the last three digits of a given telNr -int mod17(std::string telNr); // hash algorithm that takes a given telNr mod17 +typedef int (*hashFunctionPtr)( + std::string); // typedefinition of a pointer for a hashfunction; they all + // need conform to the guideline: int + // (std::string ) +int lastNumber(std::string telNr); // hash algorithm that uses only the last + // digit of a given telNr +int firstThreeNumbers(std::string telNr); // hash algorithm that uses the first + // three digits of a given telNr +int lastThreeNumbers(std::string telNr); // hash algorithm that uses the last + // three digits of a given telNr +int mod17(std::string telNr); // hash algorithm that takes a given telNr mod17 + +int mod37(std::string telNr); // hash algorithm that takes a given telNr mod37 + +int mod71(std::string telNr); // hash algorithm that takes a given telNr mod71 class HashTable { - private: - class HashFunction { // private inner class to make hash functions managable - public: - int size; - std::string name; - hashFunctionPtr algorithm; - - HashFunction(std::string name, hashFunctionPtr algorithm, int size); // constructor - }; +private: + class HashFunction { // private inner class to make hash functions managable + public: + int size; + std::string name; + hashFunctionPtr algorithm; - HashFunction availableAlgorithms[4] = { {"lastNumber", lastNumber, 10}, {"firstThreeNumbers", firstThreeNumbers, 1000}, {"lastThreeNumbers", lastThreeNumbers, 1000}, {"mod17", mod17, 17}}; - - class HashNode { // private inner class for HashNodes that have a key (which will be the telephone number) and a value of type PbEntry - public: - std::string key = ""; - PbEntry* phonebookEntry; - }; + HashFunction(std::string name, hashFunctionPtr algorithm, + int size); // constructor + }; - public: - int size; // m in lecture - int numberOfEntries; // n in lecture - HashNode* entries; // nodes of the hash table - hashFunctionPtr hashFunction; // pointer to the hash algorithm used is stored in a private variable of type hashFunctionPtr - see beginning of this file + HashFunction availableAlgorithms[6] = { + {"lastNumber", lastNumber, 10}, + {"firstThreeNumbers", firstThreeNumbers, 1000}, + {"lastThreeNumbers", lastThreeNumbers, 1000}, + {"mod17", mod17, 17}, + {"mod37", mod37, 37}, + {"mod71", mod71, 71}}; + class HashNode { // private inner class for HashNodes that have a key (which + // will be the telephone number) and a value of type PbEntry + public: + std::string key = ""; + PbEntry *phonebookEntry; + HashNode() : key(""), phonebookEntry(nullptr) {} + }; - void insert(PbEntry* entry); - const PbEntry* search(std::string key); - bool deleteItem(std::string key); - void print(); - void setHashFunction(std::string name); +public: + int size; // m in lecture + int numberOfEntries; // n in lecture + HashNode *entries; // nodes of the hash table + hashFunctionPtr hashFunction; // pointer to the hash algorithm used is stored + // in a private variable of type + // hashFunctionPtr - see beginning of this file - HashTable(); // default constructor + void insert(PbEntry *entry); + const PbEntry *search(std::string key); + bool deleteItem(std::string key); + void print(); + void setHashFunction(std::string name); + float getloadFactor(); + + HashTable(); // default constructor }; \ No newline at end of file diff --git a/Uebung 4/Uebung4_2/main.cpp b/Uebung 4/Uebung4_2/main.cpp index dcf1ec0..f4cfcb4 100644 --- a/Uebung 4/Uebung4_2/main.cpp +++ b/Uebung 4/Uebung4_2/main.cpp @@ -1,35 +1,52 @@ #include "hashTable.h" #include "pbEntry.h" -#include #include +#include + +// Function to generate random strings for our Wares. See: +// https://stackoverflow.com/a/12468109 +std::string random_string(size_t length) { + auto randchar = []() -> char { + const char charset[] = "0123456789"; + const size_t max_index = (sizeof(charset) - 1); + return charset[rand() % max_index]; + }; + std::string str(length, 0); + std::generate_n(str.begin(), length, randchar); + return str; +} int main() { - PbEntry entry1("3277971", "Norma Noe", "North Lyme Drive 30"); - PbEntry entry2("9928657", "Ashok Kumar", "Lawrence Avenue 24"); - PbEntry entry3("1674792", "Baby Doe", "North Lyme Street 34"); - PbEntry entry4("4991459", "Brett Boe", "North Lyme Road 35 "); - PbEntry entry5("1990539", "Carla Coe", "Lawrence Road 29"); - HashTable ht; - ht.insert(&entry1); - ht.insert(&entry2); - ht.insert(&entry3); - ht.insert(&entry4); - ht.insert(&entry5); - ht.print(); + PbEntry entry1("3277971", "Norma Noe", "North Lyme Drive 30"); + PbEntry entry2("9928657", "Ashok Kumar", "Lawrence Avenue 24"); + PbEntry entry3("1674792", "Baby Doe", "North Lyme Street 34"); + PbEntry entry4("4991459", "Brett Boe", "North Lyme Road 35 "); + PbEntry entry5("1990539", "Carla Coe", "Lawrence Road 29"); + HashTable ht; + ht.insert(&entry1); + ht.insert(&entry2); + ht.insert(&entry3); + ht.insert(&entry4); + ht.insert(&entry5); + for (int i = 0; i < 60; i++) { + ht.insert(new PbEntry(random_string(7), "test", "test")); + } + ht.print(); + std::cout << ht.getloadFactor() << std::endl; - // ht.setHashFunction("mod17"); - // ht.insert(&entry1); - // ht.insert(&entry2); - // ht.insert(&entry3); - // ht.insert(&entry4); - // ht.insert(&entry5); - // ht.print(); + // ht.setHashFunction("mod17"); + // ht.insert(&entry1); + // ht.insert(&entry2); + // ht.insert(&entry3); + // ht.insert(&entry4); + // ht.insert(&entry5); + // ht.print(); - // const PbEntry* s1 = ht.search("3277971"); - // std::cout << s1->toString(); - - // bool test = ht.deleteItem("3277971"); - // std::cout << test << std::endl; - // bool test2 = ht.deleteItem("3277971"); - // std::cout << test2 << std::endl; + // const PbEntry* s1 = ht.search("3277971"); + // std::cout << s1->toString(); + + // bool test = ht.deleteItem("3277971"); + // std::cout << test << std::endl; + // bool test2 = ht.deleteItem("3277971"); + // std::cout << test2 << std::endl; }