SDEV-324-81/week-14/main.cpp

313 lines
12 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Champlain College SDEV-345-81
*
* C++ Week 14 Quadratic Probing, Hash Tables - (2020/12/13)
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Modify last week's program to demonstrate quadratic hash probing when a collision occurs.
*
* LAST WEEK
* Write a menu driven program that creates a hash table using an array.
* The program should give the user the following options and should run in an infinite loop:
* 1) Insert key
* 2) Delete key
* 3) Display hash table
* 4) Find key
* The key should be a string and the program should calculate the location using a hash function.
* The program should also prompt the user when there is a collision and when the hash table is full.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Written by Llewellyn van der Merwe <llewellyn.vandermerw@mymail.champlain.edu>, December 2020
* Copyright (C) 2020. All Rights Reserved
* License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <iostream>
#include <string>
#include <limits>
using namespace std;
class HashTable {
private:
// never use this as a value ;)
const string emptyString = "|//_-++-_0.^.0_-++-_\\|";
// the size of the array
static const int tableSize = 8;
// the inserted number
int inserted = 0;
// the HashBucket table array of nodes
string HashBucket[tableSize];
// found & empty key
static const int emptyFoundKey = tableSize + 10;
// found ;)
int foundKey = emptyFoundKey;
// empty ;)
int emptyKey = emptyFoundKey;
// search for value in table
bool find(string &value) {
// get the HashBucket value of the string
int key = Hash(value);
// check if the value is found
if (HashBucket[key] == value) {
// if found set key
foundKey = key;
// found
return true;
}
// continue the search
return find(key, value);
}
// smart search by key and value
bool find(int &key, string &value) {
// always reset the found
emptyKey = emptyFoundKey;
foundKey = emptyFoundKey;
// use quadratic probing
for (int pos = 0; pos < tableSize; pos++) {
// Computing the new hash value
key = Quadratic(key, pos);
// check if the value is found
if (HashBucket[key] == value) {
// if found set key
foundKey = key;
// we found the value
return true;
} else if (HashBucket[key] == emptyString && emptyKey == emptyFoundKey) {
// if first not found set key
emptyKey = key;
// but lets continue the search since on removal
// we do not move the values to spaces
// up to fill the array from the first hash
}
}
return false;
}
// Hash function
int Hash(string key) {
int hash = 0;
int tmp = key.length();
// now loop the string value-key to get HashBucket
for (int i = 0; i < tmp; i++) {
hash = hash + (int) key[i];
}
// return the remainder
return hash % tableSize;
}
// quadratic insert function
bool insert(int &key, string &value) {
// check if key was found
if (key != emptyFoundKey && HashBucket[key] == emptyString) {
// since we have the key
// we need to do the search
// again
HashBucket[key] = value;
// count values inserted
inserted++;
// always reset just incase
emptyKey = emptyFoundKey;
return true;
}
// get the HashBucket value of the string
key = Hash(value);
// use quadratic probing
for (int pos = 0; pos < tableSize; pos++) {
// Computing the new hash value
key = Quadratic(key, pos);
if (HashBucket[key] == emptyString) {
// Break the loop after
// inserting the value
// in the table
HashBucket[key] = value;
// count values inserted
inserted++;
return true;
}
}
return false;
}
// quadratic function
int Quadratic(int key, int pos) {
// Computing the new hash value
int hash = key + pos * pos;
// return the remainder
return hash % tableSize;
}
public:
// our constructor of our HashBucket table
HashTable() {
// initialize the empty HashBucket tables
for (int i = 0; i < tableSize; i++) {
HashBucket[i] = emptyString;
}
}
// check if table is full
bool isFull() {
return inserted == tableSize;
}
// add a node value
void insert(string value) {
// get the HashBucket value of the string
int key = Hash(value);
// check if the HashBucket has a collision
if (HashBucket[key] == emptyString) {
// give success adding info
cout << "█ [Info] " << value << " - added successfully." << endl;
// new value
HashBucket[key] = value;
// count values inserted
inserted++;
}
// check if the value exist
else if (!find(value)) {
// prom the user if we should add to table
cout << "█ [Warning] Collision detected." << endl;
cout << "█ Do you still want to add: " << value << endl;
cout << "█ Enter initial [yes/no]: ";
char choice;
cin >> choice;
if ((choice == 'y' || choice == 'Y') && insert(emptyKey, value)) {
// give collision info
cout << "██████████████████████████████████████████████████████████" << endl;
cout << "█ Collision resolved!" << endl;
cout << "█ [Info] " << value << " - quadratic probing used." << endl;
} else if (choice == 'y' || choice == 'Y') {
// give error of quadratic probing failure
cout << "██████████████████████████████████████████████████████████" << endl;
cout << "█ [Error] " << value << " - not added." << endl;
cout << "█ [Error] " << " - Quadratic probing failed." << endl;
cout << "█ [Error] " << " - The array needs to be enlarged." << endl;
} else {
// give notice
cout << "█ [Notice] " << value << " - not added." << endl;
}
} else {
// give exists error
cout << "█ [Error] " << value << " - exists." << endl;
}
cout << "██████████████████████████████████████████████████████████" << endl;
return;
}
// search if the value is in the hash table
void search(string &value) {
// use the find method/function
if (find(value)) {
cout << "█ [Success] (" << foundKey << ") => " << value << " - found" << endl;
} else {
cout << "█ [Notice] " << value << " - not found" << endl;
}
cout << "██████████████████████████████████████████████████████████" << endl;
return;
}
// display the hash table
void display() {
cout << "███ THE HASH TABLE ███████████████████████████████████████" << endl;
cout << "██████████████████████████████████████████████████████████" << endl;
for (int i = 0; i < tableSize; i++) {
// only print out if bucket has values
if (HashBucket[i] != emptyString) {
cout << "█ (" << i << ") => ";
cout << HashBucket[i] << endl;
cout << "██████████████████████████████████████████████████████████" << endl;
} else {
// empty notice
cout << "█ (" << i << ") =-" << endl;
cout << "██████████████████████████████████████████████████████████" << endl;
}
}
if (isFull()) {
cout << "███ TABLE IS FULL ████████████████████████████████████████" << endl;
} else {
cout << "███ TABLE NOT FULL ███████████████████████████████████████" << endl;
}
return;
}
// delete a value from the table
void remove(string value) {
// value found so remove
if (find(value)) {
// move the next node up
HashBucket[foundKey] = emptyString;
// count value removed
inserted--;
// removed notice
cout << "█ [Success] " << value << " - removed." << endl;
} else {
// not found notice
cout << "█ [Notice] " << value << " - not found." << endl;
}
cout << "██████████████████████████████████████████████████████████" << endl;
return;
}
};
int main() {
// instantiate the table
HashTable Table;
// program loop (taken and adapted from this weeks module)
char choice = 'b';
string aKey;
// start the program
cout << "██████████████████████████████████████████████████████████" << endl;
// interact with user
while (choice != 'x') {
// check if the table is full
if (Table.isFull()) {
cout << "█ Enter first letter of "
<< "show, delete, or find: ";
} else {
cout << "█ Enter first letter of "
<< "show, insert, delete, or find: ";
}
char choice;
cin >> choice;
// clear cin stream
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
switch (choice) {
case 's':
Table.display();
break;
case 'i':
if (Table.isFull()) {
cout << "█ Table is full" << endl;
} else {
cout << "█ Enter key value to insert: ";
getline(cin, aKey);
// now insert the string
Table.insert(aKey);
}
break;
case 'd':
cout << "█ Enter key value to delete: ";
getline(cin, aKey);
// now remove the string
Table.remove(aKey);
break;
case 'f':
cout << "█ Enter key value to find: ";
getline(cin, aKey);
// now search for the string
Table.search(aKey);
break;
default:
cout << "█ Invalid entry" << endl;
break;
}
}
}